/*!
 * session.cpp
 *
 * Copyright (c) 2015, NADAL Jean-Baptiste. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 * 
 * @Author:  NADAL Jean-Baptiste
 * @Date: 19/03/2015
 *
 */

/*-------------------------------- INCLUDES ---------------------------------*/

#include <string.h>

#include "session.h"

/*-------------------------------- GLOBALE ---------------------------------*/

static struct session gSessions [MAX_SESSIONS];  // Current sessions

/*!  ----------------------------------------------------------------------------
 *  @fn new_session
 *
 *  @brief  Allocate new session object
 */
struct session *new_session (void)
{
    int i;
    time_t now = time(NULL);
    pthread_rwlock_wrlock (&gRwlock);
    for (i = 0; i < MAX_SESSIONS; i++) {
        if (gSessions[i].expire == 0 || gSessions[i].expire < now) {
            gSessions[i].expire = time(0) + SESSION_TTL;
            break;
        }
    }
    pthread_rwlock_unlock (&gRwlock);
    return i == MAX_SESSIONS ? NULL : &gSessions[i];
}


/*!  ----------------------------------------------------------------------------
 *  @fn get_session
 *
 *  @brief Get session object for the connection. Caller must hold the lock.
 */
struct session *get_session (const struct mg_connection *aConn)
{
	int i;
    const char *cookie = mg_get_header (aConn, "Cookie");
    char session_id[33];
    time_t now = time (NULL);

    mg_get_cookie (cookie, "session", session_id, sizeof(session_id));

    for (i = 0; i < MAX_SESSIONS; i++) {

        if (gSessions[i].expire != 0 &&
            gSessions[i].expire > now &&
            strcmp (gSessions[i].session_id, session_id) == 0) {
            break;
        }
    }
    return i == MAX_SESSIONS ? NULL : &gSessions[i];
}


/*!  ----------------------------------------------------------------------------
 *  @fn generate_session_id
 *
 *  @brief Generate session ID. buf must be 33 bytes in size.
 *         Note that it is easy to steal session cookies by sniffing traffic.
 *         This is why all communication must be SSL-ed.
 */
void generate_session_id (char *aBuf, const char *aRandom,
                               	 const char *anUser)
{
    mg_md5 (aBuf, aRandom, anUser, NULL);
}


/*!  ----------------------------------------------------------------------------
 *  @fn get_qsvar
 *
 *  @brief TODO.
 */
void get_qsvar (const struct mg_request_info *aRequest_info,
                const char *aName, char *aDst, size_t aDst_len)
{
    const char *qs = aRequest_info->query_string;
    mg_get_var (qs, strlen(qs == NULL ? "" : qs), aName, aDst, aDst_len);
}
