[Back]

// 
//  DotNetNuke - http://www.dotnetnuke.com
//  Copyright (c) 2002-2009
//  by DotNetNuke Corporation
// 
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
//  to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions 
//  of the Software.
// 
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
//  TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
//  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//  DEALINGS IN THE SOFTWARE.
//
// Based on
// Silverlight2Chat
// Copyright (c) 2009
// by Junnark Vicencio 
//
// The Code Project Open License (CPOL) 1.02
// http://www.codeproject.com/info/cpol10.aspx

using System.Web.Services;
using System.Web.Script.Services;

using System;
using DotNetNuke.Entities.Users;
using System.Linq;
using System.Collections.Generic;
using DotNetNuke.Services.Exceptions;
using System.Security.Cryptography;
using System.Text;
using Microsoft.VisualBasic;

namespace DotNetNuke.Modules.DNNSilverlightChat
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ScriptService()]
    public class WebService : System.Web.Services.WebService
    {
        #region InsertMessage
        [WebMethod(Description = "InsertMessage")]
        public void InsertMessage(int PortalID, int ModuleId, int UserID, string Password, int? toUserID, string messageText, string color)
        {
            if (IsValidUser(PortalID, ModuleId, UserID, Password))
            {
                DNNSilverlightChat_Message message = new DNNSilverlightChat_Message();
                message.ModuleID = ModuleId;
                message.UserID = UserID;
                message.ToUserID = toUserID;
                message.Text =  Strings.Left(messageText, 2000);
                message.Color = color;
                message.TimeStamp = DateTime.Now;

                DNNSilverlightChatDALDataContext db = new DNNSilverlightChatDALDataContext();
                db.DNNSilverlightChat_Messages.InsertOnSubmit(message);

                try
                {
                    db.SubmitChanges();
                }
                catch (Exception ex)
                {
                    Exceptions.LogException(ex);
                    throw;
                }

                // Add the message to the cache            
                List<MessageContract> messageContracts = GetCurrentMessagesFromCache(ModuleId);
                List<DNNChatUser> colDNNChatUser = GetCurrentUsersFromCache(ModuleId);

                MessageContract InsertMessageContract = new MessageContract();
                InsertMessageContract.MessageID = message.MessageID;
                InsertMessageContract.Text = message.Text;
                InsertMessageContract.UserName = colDNNChatUser.Where(x => x.UserID == message.UserID).FirstOrDefault().UserName;
                InsertMessageContract.Color = message.Color;
                InsertMessageContract.TimeStamp = message.TimeStamp;

                messageContracts.Add(InsertMessageContract);

                // Remove messages that are more than 30 seconds old
                var MessagesToDelete = from m in messageContracts
                                       where m.TimeStamp < DateTime.Now.AddSeconds(-30)
                                       select m;

                foreach (var objMessage in MessagesToDelete)
                {
                    messageContracts.Remove(objMessage);
                }

            }
        }
        #endregion

        #region GetMessages
        [WebMethod(Description = "GetMessages")]
        public List<MessageContract> GetMessages(int PortalID, int ModuleId, int UserID, string Password, int messageID, DateTime timeUserJoined)
        {
            List<MessageContract> messageContracts = new List<MessageContract>();

            if (IsValidUser(PortalID, ModuleId, UserID, Password))
            {
                // Get all messages that were not sent by the current user
                List<MessageContract> MessagesFromCache = GetCurrentMessagesFromCache(ModuleId);
                string strUsername = UserController.GetUser(PortalID, UserID, false).DisplayName;

                var messages = (from m in MessagesFromCache
                                where m.MessageID > messageID &&
                                m.TimeStamp > DateTime.Now.AddSeconds(-31) &&
                                m.UserName != strUsername
                                orderby m.MessageID ascending
                                select new { m.MessageID, m.Text, m.UserName, m.Color });

                foreach (var message in messages.ToList())
                {
                    MessageContract messageContract = new MessageContract();
                    messageContract.MessageID = message.MessageID;
                    messageContract.Text = message.Text;
                    messageContract.UserName = message.UserName;
                    messageContract.Color = message.Color;
                    messageContracts.Add(messageContract);
                }
            }

            return messageContracts;
        }
        #endregion

        #region GetUsers
        [WebMethod(Description = "GetUsers")]
        public List<DNNChatLoggedInUsers> GetUsers(int PortalID, int ModuleId, int UserID, string Password)
        {
            List<DNNChatLoggedInUsers> colDNNChatLoggedInUsers = new List<DNNChatLoggedInUsers>();

            if (IsValidUser(PortalID, ModuleId, UserID, Password))
            {
                List<DNNChatUser> colDNNChatUser = GetCurrentUsersFromCache(ModuleId);

                // Get the current user and update their last Message value
                var ChatUser = (from DNNChatUsers in colDNNChatUser
                                where DNNChatUsers.UserID == UserID
                                select DNNChatUsers).FirstOrDefault();

                if (ChatUser != null)
                {
                    ChatUser.LastMessage = DateTime.Now;
                }

                // Log out any users who have not been active
                var CACHEUsersToLogOut = from DNNChatUsers in colDNNChatUser
                                         where DNNChatUsers.LastMessage < DateTime.Now.AddMinutes(-1)
                                         select DNNChatUsers;

                foreach (var InactiveUser in CACHEUsersToLogOut)
                {
                    colDNNChatUser.Remove(InactiveUser);
                }

                // Return a list of the users as a list of DNNChatLoggedInUserss
                // get all logged in users to this room (Get from Cache)
                var loggedInUsers = from objDNNChatUser in colDNNChatUser
                                    orderby objDNNChatUser.UserName ascending
                                    group objDNNChatUser by objDNNChatUser.UserName into ChatUsers
                                    select new { ChatUsers.Key };

                foreach (var loggedInUser in loggedInUsers)
                {
                    DNNChatLoggedInUsers DNNChatLoggedInUsers = new DNNChatLoggedInUsers();
                    DNNChatLoggedInUsers.UserName = loggedInUser.Key;



                    // Get user email and convert to gravatar url
                    var loggedInUserId = (from objDnnChatUser in colDNNChatUser
                                          where objDnnChatUser.UserName == loggedInUser.Key
                                          select objDnnChatUser.UserID).FirstOrDefault();

                    if (loggedInUserId != null)
                    {
                        DNNChatLoggedInUsers.ImageUrl = GetImageUrl(PortalID, loggedInUserId);
                    }

                    colDNNChatLoggedInUsers.Add(DNNChatLoggedInUsers);
                }
            }

            return colDNNChatLoggedInUsers;
        }
        #endregion

        #region LogOutUser
        [WebMethod(Description = "LogOutUser")]
        public void LogOutUser(int PortalID, int ModuleId, int UserID, string Password, int InactiveUser)
        {
            if (IsValidUser(PortalID, ModuleId, UserID, Password))
            {
                List<DNNChatUser> colDNNChatUser = GetCurrentUsersFromCache(ModuleId);

                // Log out user
                var CACHEUserToLogOut = (from DNNChatUsers in colDNNChatUser
                                         where DNNChatUsers.UserID == InactiveUser
                                         select DNNChatUsers).FirstOrDefault();

                colDNNChatUser.Remove(CACHEUserToLogOut);

                DNNSilverlightChatDALDataContext db = new DNNSilverlightChatDALDataContext();

                // insert user "left the room" text
                DNNSilverlightChat_Message message = new DNNSilverlightChat_Message();
                message.ModuleID = ModuleId;
                message.UserID = InactiveUser;
                message.ToUserID = null;
                message.Text = UserController.GetUser(PortalID, InactiveUser, false).DisplayName + " left the room.";
                message.Color = "Gray";
                message.TimeStamp = DateTime.Now;

                db.DNNSilverlightChat_Messages.InsertOnSubmit(message);
                db.SubmitChanges();
            }
        }
        #endregion

        #region IsValidUser
        private bool IsValidUser(int PortalID, int ModuleId, int UserID, string Password)
        {
            bool boolIsValidUser = false;

            List<DNNChatUser> colDNNChatUser = GetCurrentUsersFromCache(ModuleId);

            // let's check if this authenticated user exists 
            DNNChatUser Chatuser = (from objDNNChatUser in colDNNChatUser
                                    where objDNNChatUser.UserID == UserID
                                    where objDNNChatUser.Password == Password
                                    select objDNNChatUser).FirstOrDefault();

            // if user does not exist table
            if (Chatuser == null)
            {
                IWebXAMLAuthendicationHeader objIWebXAMLAuthendicationHeader = new IWebXAMLAuthendicationHeader();
                objIWebXAMLAuthendicationHeader.PortalID = PortalID;
                objIWebXAMLAuthendicationHeader.UserID = UserID;
                objIWebXAMLAuthendicationHeader.Password = Password;
                objIWebXAMLAuthendicationHeader.ModuleId = ModuleId;

                IWebXAMLAuthendication objIWebXAMLAuthendication = new IWebXAMLAuthendication(objIWebXAMLAuthendicationHeader);
                if (!(objIWebXAMLAuthendication.IsUserValid()))
                {
                    boolIsValidUser = false;
                }
                else
                {
                    boolIsValidUser = true;
                }

                // If user is valid add them to the CACHE
                if (boolIsValidUser)
                {
                    // Remove all instances that may be in CACHE
                    var CACHEUserInstanceToLogOut = from DNNChatUsers in colDNNChatUser
                                                    where DNNChatUsers.UserID == UserID
                                                    select DNNChatUsers;

                    foreach (var InactiveUser in CACHEUserInstanceToLogOut)
                    {
                        colDNNChatUser.Remove(InactiveUser);
                    }

                    // Add the user to Cache
                    DNNChatUser loggedInUser = new DNNChatUser();
                    loggedInUser.UserID = UserID;
                    loggedInUser.LastMessage = DateTime.Now;
                    loggedInUser.UserName = UserController.GetUser(PortalID, UserID, false).DisplayName;
                    loggedInUser.Password = Password;

                    // Add the user to the cache
                    colDNNChatUser.Add(loggedInUser);
                }
            }
            else
            {
                // The user is valid and already in the CACHE
                boolIsValidUser = true;
            }

            return boolIsValidUser;
        }
        #endregion

        #region GetCurrentUsersFromCache
        private static List<DNNChatUser> GetCurrentUsersFromCache(int ModuleId)
        {
            string key = String.Format("{0}_DNNChatUser", ModuleId.ToString());
            List<DNNChatUser> colDNNChatUser;

            if (!CacheHelper.Get(key, out colDNNChatUser))
            {
                colDNNChatUser = new List<DNNChatUser>();
                CacheHelper.Add(colDNNChatUser, key);
            }
            return colDNNChatUser;
        }
        #endregion

        #region GetCurrentMessagesFromCache
        private static List<MessageContract> GetCurrentMessagesFromCache(int ModuleId)
        {
            string key = String.Format("{0}_DNNChatMessages", ModuleId.ToString());
            List<MessageContract> colDNNChatMessages;

            if (!CacheHelper.Get(key, out colDNNChatMessages))
            {
                colDNNChatMessages = new List<MessageContract>();
                CacheHelper.Add(colDNNChatMessages, key);
            }
            return colDNNChatMessages;
        }
        #endregion

        #region GetImageUrl
        private static string GetImageUrl(int PortalID, int UserID)
        {
            var dnnUser = DotNetNuke.Entities.Users.UserController.
                GetUser(PortalID, UserID, true);

            string imageUrl = "http://www.gravatar.com/avatar/";

            if (!string.IsNullOrEmpty(dnnUser.Email))
            {
                // build up image url, including MD5 hash for supplied email:
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

                UTF8Encoding encoder = new UTF8Encoding();
                MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();

                byte[] hashedBytes = md5Hasher.ComputeHash
                    (encoder.GetBytes(dnnUser.Email.ToLower()));

                StringBuilder sb = new StringBuilder(hashedBytes.Length * 2);
                for (int i = 0; i < hashedBytes.Length; i++)
                {
                    sb.Append(hashedBytes[i].ToString("X2"));
                }

                // output parameters:
                imageUrl += sb.ToString().ToLower();
                imageUrl += "?s=40";
                imageUrl += "&d=wavatar";
            }

            return imageUrl;
        }
        #endregion
    }

    #region DNNChatUser
    public class DNNChatUser
    {
        public int UserID { get; set; }
        public string UserName { get; set; }
        public System.DateTime LastMessage { get; set; }
        public string Password { get; set; }
        //public string ImageUrl { get; set; }
    }
    #endregion

    #region DNNChatLoggedInUsers
    [Serializable]
    public class DNNChatLoggedInUsers
    {
        public string UserName { get; set; }
        public string ImageUrl { get; set; }


    }
    #endregion

    #region MessageContract
    [Serializable]
    public class MessageContract
    {
        public int MessageID { get; set; }
        public string Text { get; set; }
        public string UserName { get; set; }
        public string Color { get; set; }
        public DateTime TimeStamp { get; set; }
    }
    #endregion
}