/*
 * @(#)Accounts.cpp
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 2001-2004 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 "Exception.h"
#include "StringBuffer.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 Exception("ID already in use.");

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

		pthread_mutex_unlock(&mutex);
	}
	catch (Exception *exception) {
		pthread_mutex_unlock(&mutex);
		throw exception;
	}
}

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 (Exception *exception) {
		pthread_mutex_unlock(&mutex);
		throw exception;
	}
}

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 Exception("Unknown user.");
		if (strcmp(passwd2, passwd3) != 0)
			throw new Exception("Invalid password.");

		pthread_mutex_unlock(&mutex);
	}
	catch (Exception *exception) {
		pthread_mutex_unlock(&mutex);
		throw exception;
	}
}

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

	FILE *in = fopen(config.getAccountsFile(), "r");
	if (in == NULL)
		throw new Exception("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 (Exception *exception) {
		pthread_mutex_unlock(&mutex);
		throw exception;
	}
}

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

	FILE *in = fopen(config.getAccountsFile(), "r");
	if (in == NULL)
		throw new Exception(S.e + "Cannot open " + config.getAccountsFile());
	StringBuffer sb = new StringBuffer(10000);
	while (true) {
		int ch = fgetc(in);
		if (ch == EOF)
			break;
		sb.append((char)ch);
	}
	fclose(in);

	for (int p0 = 0; ; p0++) {
		p0 = sb.indexOf(key.getBytes(), p0);
		if (p0 < 0)
			break;
		if (p0 > 0 && sb.charAt(p0 - 1) != '\n')
			continue;
		int p1 = sb.indexOf("\n", p0);
		if (p1 < 0)
			p1 = sb.length() - 1;
		sb.delete_(p0, p1 + 1);
		sb.insert(p0, newItem);
	}

	FILE *out = fopen(config.getAccountsFile(), "w");
	if (out == NULL)
		throw new Exception(S.e + "Cannot write " + config.getAccountsFile());
	String str = new String(sb);
	fwrite(str.getBytes(), 1, str.length(), out);
	fclose(out);
}

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

Accounts *accounts;
