/*
 * @(#)Accounts.cpp
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 2001 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDWserver.cpp for details.
 *
 * Jörg Haeger, 25.04.2001
 */

#include <stdio.h>
#include <string.h>
#include "Accounts.h"
#include "Config.h"
#include "Error.h"

Accounts::Accounts()
{
	pthread_mutex_init(&mutex, NULL);
}

Accounts::~Accounts()
{
}

void Accounts::add(const char *ID, const char *passwd, const char *eMail)
{
	char ID2[strlen(ID) + 1];
	strcpy(ID2, ID);
	replaceColons(ID2);

	char passwd2[strlen(passwd) + 1];
	strcpy(passwd2, passwd);
	replaceColons(passwd2);

	char eMail2[strlen(eMail) + 1];
	strcpy(eMail2, eMail);
	replaceColons(eMail2);

	try {
		pthread_mutex_lock(&mutex);

		char passwd3[1024], eMail3[sizeof passwd3];
		getByID(ID2, passwd3, eMail3, sizeof passwd3);
		if (passwd3[0] != 0)
			throw new Error("ID already in use.");

		FILE *out = fopen(config.getAccountsFile(), "a");
		if (out == NULL)
			throw new Error("Cannot write to the accounts file.");
		fprintf(out, "%s:%s:%s\n", ID2, passwd2, eMail2);
		fclose(out);

		pthread_mutex_unlock(&mutex);
	}
	catch (Error *error) {
		pthread_mutex_unlock(&mutex);
		throw error;
	}
}

void Accounts::changePassword(const char *ID, const char *newPasswd)
{
	char ID2[strlen(ID) + 1];
	strcpy(ID2, ID);
	replaceColons(ID2);

	char passwd2[strlen(newPasswd) + 1];
	strcpy(passwd2, newPasswd);
	replaceColons(passwd2);

	try {
		pthread_mutex_lock(&mutex);

		char oldPasswd[1024], eMail[sizeof oldPasswd];
		getByID(ID, oldPasswd, eMail, sizeof oldPasswd);

		char newItem[strlen(ID2) + 1 + strlen(passwd2)
			+ 1 + strlen(eMail) + 1];
		sprintf(newItem, "%s:%s:%s\n", ID2, passwd2, eMail);
		replace(ID, newItem);

		pthread_mutex_unlock(&mutex);
	}
	catch (Error *error) {
		pthread_mutex_unlock(&mutex);
		throw error;
	}
}

void Accounts::check(const char *ID, const char *passwd)
{
	char ID2[strlen(ID) + 1];
	strcpy(ID2, ID);
	replaceColons(ID2);

	char passwd2[strlen(passwd) + 1];
	strcpy(passwd2, passwd);
	replaceColons(passwd2);

	try {
		pthread_mutex_lock(&mutex);

		char passwd3[1024], eMail3[sizeof passwd3];
		getByID(ID2, passwd3, eMail3, sizeof passwd3);
		if (passwd3[0] == 0)
			throw new Error("Unknown user.");
		if (strcmp(passwd2, passwd3) != 0)
			throw new Error("Invalid password.");

		pthread_mutex_unlock(&mutex);
	}
	catch (Error *error) {
		pthread_mutex_unlock(&mutex);
		throw error;
	}
}

void Accounts::getByID(const char *ID, char *passwd, char *eMail, int size)
{
	if (size < 20)
		throw new Error("Accounts::getByID: size = %d.", size);

	FILE *in = fopen(config.getAccountsFile(), "r");
	if (in == NULL)
		throw new Error("Cannot open %s.", config.getAccountsFile());

	char lineStr[1024],
		ID2[sizeof lineStr], passwd2[sizeof lineStr],
		eMail2[sizeof lineStr];
	ID2[0] = 0;
	passwd[0] = eMail[0] = 0;
	while (fgets(lineStr, sizeof lineStr, in) != NULL)
	{
		if (sscanf(lineStr, "%[^:]:%[^:]:%[^:\n]",
			ID2, passwd2, eMail2) != 3)
			continue;
		if (strcmp(ID2, ID) == 0)
			break;
	}
	fclose(in);

	if (strcmp(ID2, ID) != 0)
		return;

	strncpy(passwd, passwd2, size);
	passwd[size - 1] = 0;
	strncpy(eMail, eMail2, size);
	eMail[size - 1] = 0;
}

void Accounts::remove(const char *ID)
{
	try {
		pthread_mutex_lock(&mutex);
		replace(ID, "");
		pthread_mutex_unlock(&mutex);
	}
	catch (Error *error) {
		pthread_mutex_unlock(&mutex);
		throw error;
	}
}

void Accounts::replace(const char *ID, const char *newItem)
{
	char ID2[strlen(ID) + 1];
	strcpy(ID2, ID);
	replaceColons(ID2);

	FILE *in = NULL, *out = NULL;
	char tmpFile[1024];
	try {
		in = fopen(config.getAccountsFile(), "r");
		if (in == NULL)
			throw new Error("Cannot open %s.", config.getAccountsFile());

		snprintf(tmpFile, sizeof tmpFile, "%s.new",
			config.getAccountsFile());
		out = fopen(tmpFile, "w");
		if (out == NULL)
			throw new Error("Cannot create %s.", config.getAccountsFile());

		char lineStr[1024];
		while (fgets(lineStr, sizeof lineStr, in) != NULL)
		{
			char ID3[sizeof lineStr];
			if (sscanf(lineStr, "%[^:]", ID3) == 1
				&& ID3[0] != '#'
				&& strcmp(ID3, ID2) == 0)
				fprintf(out, "%s", newItem);
			else
				fprintf(out, "%s", lineStr);
		}

		fclose(out);
		fclose(in);
		rename(tmpFile, config.getAccountsFile());
	}
	catch (Error *error) {
		if (out != NULL)
			fclose(out);
		if (in != NULL)
			fclose(in);
		remove(tmpFile);
		throw error;
	}
}

char *Accounts::replaceColons(char *str)
{
	char *ptr = str;
	while (*ptr != 0)
	{
		if (*ptr == ':')
			*ptr = '_';
		ptr++;
	}
	return str;
}

Accounts *accounts;
