/*
 * Copyright 2008 The Yacafe Project. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE YACAFE PROJECT ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE YACAFE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the Yacafe Project.
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sample.h"

#define PASSWORD_LENGTH_MIN "4"
#define PASSWORD_LENGTH_MAX "16"

#define PASSWORD_ERROR_VERIFY          (0x01 << 0)
#define PASSWORD_ERROR_EMPTY           (0x01 << 1)
#define PASSWORD_ERROR_LENGTH          (0x01 << 2)
#define PASSWORD_ERROR_INVALID         (0x01 << 3)
#define PASSWORD_ERROR_PROPERTY_CREATE (0x01 << 4)
#define PASSWORD_ERROR_PROPERTY_LOAD   (0x01 << 5)

#define PASSWORD_MESSAGE_SUCCESS         "パスワードを変更しました"
#define PASSWORD_MESSAGE_FAILURE         "パスワードを変更することが出来ません"
#define PASSWORD_MESSAGE_PREFIX          "<br/>\n　・"
#define PASSWORD_MESSAGE_VERIFY          "新しいパスワードが一致しません"
#define PASSWORD_MESSAGE_EMPTY           "新しいパスワードが入力されていません"
#define PASSWORD_MESSAGE_LENGTH          "新しいパスワードは " PASSWORD_LENGTH_MIN " 文字以上 " PASSWORD_LENGTH_MAX " 文字以内で入力して下さい"
#define PASSWORD_MESSAGE_INVALID         "新しいパスワードは半角の英数または記号で入力して下さい"
#define PASSWORD_MESSAGE_PROPERTY_CREATE "システムエラーが発生しました"
#define PASSWORD_MESSAGE_PROPERTY_LOAD   "定義ファイル " USER_PROPERTY_FILE " をロード出来ません"

static int
password_modify(request_t *request);
static int
password_modify_core(const char *password);

char *
action(request_t *request, response_t *response, session_t *session)
{
	char *submit;
	int err;
	response_node_t *node;
	xstring_t *message;

	submit = request_item_get_value(request_get_item_by_name(request, "submit"));

	if(submit)
	{
		err = password_modify(request);

		if(err)
		{
			goto ERROR;
		}

		node = response_append_node(response, "message");

		response_node_append_property(node, "text", PASSWORD_MESSAGE_SUCCESS);

		response_node_append_property(node, "class", "success");
	}

	return strutil_dup("success");

ERROR:
	message = xstring_create(PASSWORD_MESSAGE_FAILURE);

	if(err & PASSWORD_ERROR_VERIFY)
	{
		xstring_concat(message, PASSWORD_MESSAGE_VERIFY, PASSWORD_MESSAGE_PREFIX);
	}

	if(err & PASSWORD_ERROR_EMPTY)
	{
		xstring_concat(message, PASSWORD_MESSAGE_EMPTY, PASSWORD_MESSAGE_PREFIX);
	}

	if(err & PASSWORD_ERROR_LENGTH)
	{
		xstring_concat(message, PASSWORD_MESSAGE_LENGTH, PASSWORD_MESSAGE_PREFIX);
	}

	if(err & PASSWORD_ERROR_INVALID)
	{
		xstring_concat(message, PASSWORD_MESSAGE_INVALID, PASSWORD_MESSAGE_PREFIX);
	}

	if(err & (PASSWORD_ERROR_VERIFY | PASSWORD_ERROR_EMPTY | PASSWORD_ERROR_LENGTH | PASSWORD_ERROR_INVALID))
	{
		response_node_append_property(response_append_node(response, "password"), "class", "error");

		response_node_append_property(response_append_node(response, "verify"), "class", "error");
	}

	if(err & PASSWORD_ERROR_PROPERTY_CREATE)
	{
		xstring_concat(message, PASSWORD_MESSAGE_PROPERTY_CREATE, PASSWORD_MESSAGE_PREFIX);
	}

	if(err & PASSWORD_ERROR_PROPERTY_LOAD)
	{
		xstring_concat(message, PASSWORD_MESSAGE_PROPERTY_LOAD, PASSWORD_MESSAGE_PREFIX);
	}

	node = response_append_node(response, "message");

	response_node_append_property(node, "text", xstring_raw(message));

	response_node_append_property(node, "class", "failure");

	xstring_destroy(message);

	return strutil_dup("success");
}

static int
password_modify(request_t *request)
{
char *password, *verify;
int   len, i, err = 0;

	password = request_item_get_value(request_get_item_by_name(request, "password"));

	verify   = request_item_get_value(request_get_item_by_name(request, "verify"));

	if(!strutil_isequal(password, verify))
	{
		err = PASSWORD_ERROR_VERIFY;

		goto ERROR;
	}

	if(strutil_isempty(password))
	{
		err = PASSWORD_ERROR_EMPTY;

		goto ERROR;
	}

	len = strlen(password);

	if(len < strtol(PASSWORD_LENGTH_MIN, NULL, 10) || len > strtol(PASSWORD_LENGTH_MAX, NULL, 10))
	{
		err = PASSWORD_ERROR_LENGTH;

		goto ERROR;
	}

	for(i = 0; i < len; i++)
	{
		if(!isprint(password[i]))
		{
			err = PASSWORD_ERROR_INVALID;

			goto ERROR;
		}
	}

	err = password_modify_core(password);

ERROR:
	return err;
}

static int
password_modify_core(const char *password)
{
property_t *property;
int         err;

	property = property_create();

	if(!property)
	{
		err = PASSWORD_ERROR_PROPERTY_CREATE;

		goto ERROR;
	}

	err = property_load(property, USER_PROPERTY_FILE);

	if(err)
	{
		err = PASSWORD_ERROR_PROPERTY_LOAD;
	}

	property_item_set_value(property_get_item_by_name(property, "PASSWORD"), password);

	property_save(property, USER_PROPERTY_FILE);

ERROR:
	property_destroy(property);

	return err;
}
