Index: pages/activate/[id].js
===================================================================
--- pages/activate/[id].js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
+++ pages/activate/[id].js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -0,0 +1,81 @@
+import React from 'react'
+
+import { useRouter } from 'next/router'
+
+import { useEffect, useState } from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+
+import { setStyle } from '../../redux/reducers/styleSlice'
+
+import Head from 'next/head'
+
+import axios from "axios";
+
+const Activate = (props) => {
+    const dispatch = useDispatch();
+
+    const router = useRouter();
+
+    const styleState = useSelector(state => state.style);
+    
+    const [activated, setActivated] = useState(false);
+    
+    useEffect(() => {
+        // display loading screen
+        dispatch(setStyle({
+            ...styleState.style,
+            displayLoadingScreen: true,
+        }));
+
+        const emailActivationId = props.id;
+
+        axios.get(`/api/postgre/activate/${emailActivationId}?action=activate_account`).then(res => {
+            if (res.data?.success) {
+                setActivated(true);
+            }
+            
+            dispatch(setStyle({
+                ...styleState.style,
+                displayLoadingScreen: false,
+            }));
+        });
+    }, []);
+
+    function goHome() {
+        router.push('/');
+    }
+
+    return (
+        <>
+            <Head>
+                <title>Caessino - Activate account</title>
+            </Head>
+
+            <div className="fullscreen fs-centered activateScreen">
+                { activated ? (
+                    <div>
+                        <h3>Your account is activated.</h3>
+                        <h3>You may now login at Caessino.</h3>
+                        <button onClick={() => goHome()} className="primaryButton">Go To The Homepage</button>
+                    </div>
+                ) : (
+                    <div>
+                        <h3>Wrong email activation id.</h3>
+                        <h3>We were unable to activate your account.</h3>
+                        <button onClick={() => goHome()} className="primaryButton">Go To The Homepage</button>
+                    </div>
+                )}
+            </div>
+        </>
+    )
+}
+
+export default Activate
+
+export async function getServerSideProps(context) {
+    return {
+      props: {
+        id: context.query.id
+      },
+    }
+  }
Index: pages/admin/index.js
===================================================================
--- pages/admin/index.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
+++ pages/admin/index.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -0,0 +1,17 @@
+import Head from 'next/head'
+
+import React from 'react'
+
+const Admin = () => {
+  return (
+    <div>
+        <Head>
+            <title>Caessino - Activate account</title>
+        </Head>
+        
+        Admin
+    </div>
+  )
+}
+
+export default Admin
Index: pages/api/blackjack/gameStates.js
===================================================================
--- pages/api/blackjack/gameStates.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/blackjack/gameStates.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -14,4 +14,6 @@
 export let game = {
   credits: -1,
+  username: '',
+  displayName: '',
   deck: [...deck],
   status: '_1_room_created',      // statuses: _1_room_created, _2_made_initial_bet, _3_made_side_bet, _4_cards_on_the_table, _5_game_over
Index: pages/api/blackjack/index.js
===================================================================
--- pages/api/blackjack/index.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/blackjack/index.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -11,7 +11,7 @@
  * Set up a room
  */
-function createARoom(session_id) {
+function createARoom(session_id, displayName, username) {
   let room = {
-    ...game, playerCards: [...game.playerCards], dealerCards: [...game.dealerCards],
+    ...game, displayName: displayName, username: username, playerCards: [...game.playerCards], dealerCards: [...game.dealerCards],
   }
 
@@ -241,4 +241,6 @@
         rooms[session_id] = room;
 
+        update_rooms_to_database();
+
         if (room.sideBetName !== '' && room.sideBetName !== 'none') {
           room.sideBetEarnings = calculateSideBetEarnings(room);
@@ -257,6 +259,4 @@
           
           rooms[session_id] = room;
-
-          update_rooms_to_database();
 
           axios.get(`${process.env.HOME_URL}/api/postgre/?action=add_credits&session_id=${session_id}&credits=${room.sideBetEarnings}`).then(postgreRes => {
@@ -348,24 +348,4 @@
     /**
      * /---------------------- GET ----------------------/
-     * Remove a room from the rooms array.
-     * @action remove_room
-     * @param session_id
-     */
-    if (req.query.action === 'remove_room' && req.query?.session_id) {
-      const session_id = req.query.session_id;
-
-      if (rooms[session_id] !== undefined) {
-        delete rooms[session_id];
-      }
-      
-      res.json({
-        success: true,
-      })
-            
-      update_rooms_to_database();
-    }
-
-    /**
-     * /---------------------- GET ----------------------/
      * Updates the state periodically
      * @action update_state
@@ -399,5 +379,5 @@
           }
           else {
-            createARoom(session_id);
+            createARoom(session_id, postgreRes.data?.displayName, postgreRes.data?.username);
           }
     
Index: pages/api/poker/gameStates.js
===================================================================
--- pages/api/poker/gameStates.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/poker/gameStates.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -54,5 +54,5 @@
  */
 
-export function createTable(playerId, playerName, tableName) {
+export function createTable(playerId, playerName, tableName, username) {
     const tableId = uuidv4();
 
@@ -75,4 +75,5 @@
             id: playerId,
             table: tableId,
+            username: username,
             credits: 0,
             status: '_1_just_entered',
Index: pages/api/poker/index.js
===================================================================
--- pages/api/poker/index.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/poker/index.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -198,6 +198,7 @@
          * @param tableId
          * @param displayName
-         */
-         if (req.query.action === 'join_a_table' && req.query?.session_id && req.query?.tableId && req.query?.displayName) {
+         * @param username
+         */
+         if (req.query.action === 'join_a_table' && req.query?.session_id && req.query?.tableId && req.query?.displayName && req.query?.username) {
             if (req.query.tableId.length > 0) {
                 const { success } = getTableAndPlayer(req.query.session_id);
@@ -210,4 +211,5 @@
                             id: req.query.session_id,
                             table: req.query.tableId,
+                            username: req.query.username,
                             credits: 0,
                             status: '_1_just_entered',
@@ -241,10 +243,11 @@
          * @param displayName
          * @param tableName
-         */
-        if (req.query.action === 'create_a_table' && req.query?.session_id && req.query?.displayName && req.query?.tableName) {
+         * @param username
+         */
+        if (req.query.action === 'create_a_table' && req.query?.session_id && req.query?.displayName && req.query?.tableName && req.query?.username) {
             const { success } = getTableAndPlayer(req.query.session_id);
 
             if (!success) {
-                createTable(req.query.session_id, req.query.displayName, req.query.tableName);
+                createTable(req.query.session_id, req.query.displayName, req.query.tableName, req.query.username);
             }
 
@@ -305,4 +308,5 @@
                         success: true,
                         displayName: postgreRes.data?.displayName,
+                        username: postgreRes.data?.username,
                         session_id: postgreRes.data?.session_id,
                         credits: postgreRes.data?.credits,
Index: pages/api/postgre/activate/[id].js
===================================================================
--- pages/api/postgre/activate/[id].js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
+++ pages/api/postgre/activate/[id].js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -0,0 +1,29 @@
+import axios from "axios";
+
+export default function handler(req, res) {
+    /**
+     * GET method
+     */
+    if (req.method === 'GET') {
+        /**
+         * /---------------------- GET ----------------------/
+         * Activate account
+         * @action activate_account
+         * @param id emailActivationId
+         */
+        if (req.query?.action === 'activate_account' && req.query?.id) {
+            const emailActivationId = req.query.id
+
+            axios.get(`${process.env.HOME_URL}/api/postgre/?action=activate_account&emailActivationId=${emailActivationId}`).then(postgreRes => {
+                if (postgreRes.data?.success) {
+                    res.json({
+                        success: true,
+                    })
+                }
+                else {
+                    res.end();
+                }
+            });
+        }
+    }
+}
Index: pages/api/postgre/index.js
===================================================================
--- pages/api/postgre/index.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/postgre/index.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -6,4 +6,6 @@
 
 const crypto = require('crypto');
+
+const nodemailer = require('nodemailer');
 
 import { progressRoundTillTheEnd } from '../poker/tableSpecific';
@@ -214,4 +216,31 @@
     /**
      * /---------------------- GET ----------------------/
+     * Activates an user account if not activated.
+     * @action activate_account
+     * @param emailActivationId
+     */
+    if (req.query?.action === 'activate_account' && req.query?.emailActivationId) {
+      pool.query('SELECT * FROM users WHERE email_activation_id = $1', [req.query.emailActivationId], (error, results) => {
+        if (error) throw error;
+
+        if (results.rows.length > 0) {
+          pool.query('UPDATE users SET activated = $1 WHERE email_activation_id = $2', [true, req.query.emailActivationId], (error, results) => {
+            if (error) throw error;
+
+            res.json({
+              success: true,
+            })
+          });
+        }
+        else {
+          res.json({
+            success: false,
+          })
+        }
+      });
+    }
+
+    /**
+     * /---------------------- GET ----------------------/
      * Checks if the player is logged in, and returns his session if so.
      * @action check_if_logged_in
@@ -226,4 +255,5 @@
           success: true,
           displayName: session.displayName,
+          username: session.username,
           session_id: session.id,
           credits: session.credits,
@@ -254,8 +284,25 @@
 
         sessions.splice(sessions.indexOf(session), 1);
-
-        axios.get(`${process.env.HOME_URL}/api/blackjack/?action=remove_room&session_id=${session_id}`);
-
         update_sessions_to_database();
+
+        // remove player from games:
+        if (rooms[session_id] !== undefined) {
+          delete rooms[session_id];
+          update_rooms_to_database();
+        }
+
+        if (game.players?.map(e=>e.session_id).indexOf(session_id) !== -1) {
+          game.players?.splice(game.players?.map(e=>e.session_id).indexOf(session_id), 1);
+          update_game_to_database();
+        }
+
+        tables.forEach(table => {
+          table.players?.forEach(player => {
+            if (player.id === session_id) {
+              player.isGhost = true;
+            }
+          })
+        })
+        update_tables_to_database();
       }
 
@@ -480,4 +527,18 @@
     if (body?.action === 'register') {
       // checks
+      if (body?.email == "undefined" || body?.email == "null" || body?.email == "") {
+        res.json({
+          success: false,
+          message: 'Email is required',
+        });
+        return ;
+      }
+      if (!body?.email?.includes('@') || body?.email?.indexOf('@', body?.email?.indexOf('@')+1) !== -1) {
+        res.json({
+          success: false,
+          message: 'Not a valid email',
+        });
+        return ;
+      }
       if (body?.username == "undefined" || body?.username == "null" || body?.username == "") {
         res.json({
@@ -535,6 +596,8 @@
         }
 
+        const emailActivationId = uuidv4();
+
         // store user in database
-        pool.query('INSERT INTO users (username, password, salt) VALUES ($1, $2, $3)', [body.username, hashedPassword, salt], (error, usersResults) => {
+        pool.query('INSERT INTO users (username, password, salt, email, email_activation_id, activated) VALUES ($1, $2, $3, $4, $5, $6)', [body.username, hashedPassword, salt, body.email, emailActivationId, false], (error, usersResults) => {
           if (error) throw error;
 
@@ -544,4 +607,6 @@
             pool.query('INSERT INTO stats (username, blackjack_games, roulette_games, poker_games, blackjack_won_games, roulette_won_games, poker_won_games, money_bet, money_earned) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)', [body.username, 0, 0, 0, 0, 0, 0, 0, 0], (error, statsResults) => {
               if (error) throw error;
+
+              sendMailForActivation(body.displayName, body.email, emailActivationId);
 
               res.json({
@@ -604,8 +669,18 @@
           if (usersResults.rows.length > 0) {
             const user = usersResults.rows[0];
+
             const salt = user.salt;
             const hashedPassword = crypto.pbkdf2Sync(body.password, salt, 1000, 64, 'sha512').toString('hex');
 
             if (hashedPassword === user.password) {
+              if (user.activated === "false") {
+                res.json({
+                  success: false,
+                  message: 'Account not activated. Check your email.',
+                })
+
+                return ;
+              }
+
               pool.query('SELECT * FROM players WHERE username = $1', [body.username], (error, playersResults) => {
                 if (playersResults.rows.length > 0) {
@@ -658,4 +733,83 @@
 }
 
+// Mailing
+const transporter = nodemailer.createTransport({
+  service: 'gmail',
+  auth: {
+      user: process.env.GOOGLE_EMAIL,
+      pass: process.env.GOOGLE_APP_PASSWORD,
+  }
+})
+
+function sendMailForActivation(displayName, userEmail, emailActivationId) {
+  const message = {
+      from: process.env.GOOGLE_EMAIL,
+      to: userEmail,
+      subject: "Caessino - Activate your account",
+      html: `
+          <h4>Hello, ${displayName}</h4>
+          <p>Thank you for creating an account at Caessino. Just one more step and you can start enjoying the games!</p>
+          <p>To activate your account please follow this link: <a target="_blank" href="${process.env.HOME_URL}/activate/${emailActivationId}">Activate account</a>
+          <br/>
+          <p>Cheers and happy playing,</p>
+          <p>The Team ESS</p>
+      `
+  }
+
+  transporter.sendMail(message, (err, data) => {
+      if (err) {
+          console.log(err);
+      }
+  })
+}
+
+let mailSentTo = {
+  poker: [],
+  roulette: [],
+  blackjack: [],
+}
+function sendMailForGameCompletition(game, username, displayName) {
+  return ;
+
+  const msgPoker = 'Your game was played to the end by the computer with the following rules:<br/>1. No more bets were made by any player;<br/>2. Cards were dealt normally like they would be under normal circumstances;<br/>3. Credits were given to the winners and taken from the losers.';
+  const msgRoulette = 'If you reconnect immediately, you can catch this ongoing game. But don\'t worry if you can\'t! If you win, credits will be awarded to you.';
+  const msgBlackjack = 'You can now continue playing your game.';
+  
+  pool.query('SELECT * FROM users WHERE username = $1', [username], (error, results) => {
+    if (error) throw error;
+
+    if (results.rows.length > 0) {
+      const userEmail = results.rows[0].email;
+
+      if ((game === 'poker' && mailSentTo.poker.indexOf(userEmail) === -1) ||
+          (game === 'roulette' && mailSentTo.roulette.indexOf(userEmail) === -1) ||
+          (game === 'blackjack' && mailSentTo.blackjack.indexOf(userEmail) === -1))
+      {
+        const message = {
+          from: process.env.GOOGLE_EMAIL,
+          to: userEmail,
+          subject: "Caessino - Server is back online",
+          html: `
+            <h4>Hello, ${displayName}</h4>
+            <p>We are writing to inform you that the server is back online.</p>
+            <p>We know that you were in the middle of playing ${game}, and we apologize for the interrupt.</p>
+            <p>${game === 'poker' ? msgPoker : game === 'roulette' ? msgRoulette : msgBlackjack}</p>
+            <br/>
+            <p>All the best,</p>
+            <p>The Team ESS</p>
+            `
+        }
+
+        transporter.sendMail(message, (err, data) => {
+          if (err) {
+              console.log(err);
+          }
+        })
+
+        mailSentTo[game].push(userEmail)
+      }
+    }
+  });
+}
 
 /**
@@ -708,4 +862,14 @@
     })
 
+    tables.forEach(table => {
+      if (table.ended) {
+        table.players?.forEach(player => {
+          if (!player.isGhost) {
+            sendMailForGameCompletition('poker', player.username, player.displayName);
+          }
+        })
+      }
+    })
+
     cleanTables();
 
@@ -731,4 +895,8 @@
 
     game = JSON.parse(results?.rows[0]?.data || []);
+
+    game.players?.forEach(player => {
+      sendMailForGameCompletition('roulette', player.username, player.name);
+    })
 
     game.loaded = true;
@@ -767,4 +935,8 @@
         rooms[room.id] = {...room, id: ''}
       })
+
+      tmpRooms.forEach(room => {
+        sendMailForGameCompletition('blackjack', room.username, room.displayName);
+      })
       
       rooms["loaded"] = true;
Index: pages/api/roulette/gameStates.js
===================================================================
--- pages/api/roulette/gameStates.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/roulette/gameStates.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -26,4 +26,6 @@
     game.status = '_1_ongoing_timer';
 
+    let inactivePlayers = []
+
     game.players.forEach(player => {
         player.whichBets = [];
@@ -37,5 +39,17 @@
         player.status = '_1_no_placed_bet';
         player.gotResults = false;
+
+        const d = Date.now();
+
+        if (d - player.lastActivity > 200000) {
+            inactivePlayers.push(player);
+        }
     })
+
+    for (let i = 0; i < inactivePlayers.length; i++) {
+        if (game.players.indexOf(inactivePlayers[i]) !== -1) {
+            game.players.splice(game.players.indexOf(inactivePlayers[i]), 1);
+        }
+    }
 }
 
@@ -68,8 +82,10 @@
 }
 
-export function addPlayer(session_id, name) {
+export function addPlayer(session_id, name, username) {
     if (game.players.map(e=>e.session_id).indexOf(session_id) === -1) {
         game.players.push({
+            lastActivity: Date.now(),
             session_id: session_id,
+            username: username,
             name: name,
             whichBets: [],
Index: pages/api/roulette/index.js
===================================================================
--- pages/api/roulette/index.js	(revision 55701f0270de2168597a7ca5d1a05ae6a66f516b)
+++ pages/api/roulette/index.js	(revision e007fcdfa1962fb2f1a22d233c554eec360f982b)
@@ -78,4 +78,5 @@
                         },
                         player.credits = postgreRes.data?.credits;
+                        player.lastActivity = Date.now();
                     }
                 });
@@ -97,4 +98,5 @@
 
             let extraAction = "";
+            let extraAction2 = "";
             let magicNumber = -1;
             let winningBets = [];
@@ -107,4 +109,7 @@
 
                     player.gotResults = true;
+                }
+                if (game.timeToStart > game.COUNTDOWN_FROM + game.WAIT_BEFORE - 15) {
+                    extraAction2 = "keep_alert";
                 }
             }
@@ -121,4 +126,5 @@
                 },
                 extraAction: extraAction,
+                extraAction2: extraAction2,
                 magicNumber: magicNumber,
                 winningBets: winningBets,
@@ -138,5 +144,5 @@
             axios.get(`${process.env.HOME_URL}/api/postgre?action=check_if_logged_in&session_id=${session_id}`).then(postgreRes => {
                 if (postgreRes.data?.success) {
-                    addPlayer(session_id, postgreRes.data?.displayName);
+                    addPlayer(session_id, postgreRes.data?.displayName, postgreRes.data?.username);
                 
                     res.json({
