Skip to content

Instantly share code, notes, and snippets.

@parzibyte
Created September 9, 2022 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save parzibyte/8b43eccf02ecbeb61f9ee55ff06c118e to your computer and use it in GitHub Desktop.
Save parzibyte/8b43eccf02ecbeb61f9ee55ff06c118e to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <unistd.h>
#define MAXIMA_LONGITUD_CADENA 1000
#define NOMBRE_ARCHIVO_CLIENTES "clientes.txt"
#define NOMBRE_ARCHIVO_ADMINISTRADOR "administrador.txt"
#define DELIMITADOR_CLIENTES ","
#define DELIMITADOR_ADMINISTRADOR ","
#define ESTADO_HABILITADO 1
#define ESTADO_DESHABILITADO 0
#define LONGITUD_TABLA -18
#define SALDO_POR_DEFECTO 1000.00
#define CANTIDAD_CIFRAS_NUMERO_CUENTA 10
struct NodoDeCliente
{
char nombre[MAXIMA_LONGITUD_CADENA];
char identificacion[MAXIMA_LONGITUD_CADENA];
char correoElectronico[MAXIMA_LONGITUD_CADENA];
char palabraSecreta[MAXIMA_LONGITUD_CADENA];
char numeroCuenta[MAXIMA_LONGITUD_CADENA];
double saldo;
int habilitado;
struct NodoDeCliente *siguiente;
};
struct Administrador
{
char correo[MAXIMA_LONGITUD_CADENA];
char palabraSecreta[MAXIMA_LONGITUD_CADENA];
};
void consumirNuevaLinea(void)
{
int c;
do
{
c = getchar();
} while (c != EOF && c != '\n');
}
void agregarNodoALista(struct NodoDeCliente **nodo, char *nombre, char *identificacion, char *correoElectronico, char *palabraSecreta, char *numeroCuenta, double saldo, int habilitado)
{
struct NodoDeCliente *nuevoNodo = malloc(sizeof(struct NodoDeCliente));
strcpy(nuevoNodo->nombre, nombre);
strcpy(nuevoNodo->identificacion, identificacion);
strcpy(nuevoNodo->correoElectronico, correoElectronico);
strcpy(nuevoNodo->palabraSecreta, palabraSecreta);
strcpy(nuevoNodo->numeroCuenta, numeroCuenta);
nuevoNodo->saldo = saldo;
nuevoNodo->habilitado = habilitado;
nuevoNodo->siguiente = NULL;
if ((*nodo) == NULL)
{
*nodo = nuevoNodo;
}
else
{
agregarNodoALista(&(*nodo)->siguiente, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, saldo, habilitado);
}
}
void imprimirLineaSeparadora()
{
int i;
for (i = 0; i < 7; i++)
{
printf("+");
int x;
for (x = 0; x < abs(LONGITUD_TABLA); x++)
{
printf("-");
}
}
printf("+\n");
}
void listarUsuarios(struct NodoDeCliente *nodo)
{
imprimirLineaSeparadora();
printf("|%*s|%*s|%*s|%*s|%*s|%*s|%*s|\n",
LONGITUD_TABLA, "Nombre", LONGITUD_TABLA, "Identificacion", LONGITUD_TABLA, "Correo", LONGITUD_TABLA, "Palabra secreta", LONGITUD_TABLA, "No. Cuenta", LONGITUD_TABLA, "Saldo", LONGITUD_TABLA, "Habilitado");
imprimirLineaSeparadora();
while (nodo != NULL)
{
printf("|%*s|%*s|%*s|%*s|%*s|%*lf|%*s|\n",
LONGITUD_TABLA, nodo->nombre, LONGITUD_TABLA, nodo->identificacion, LONGITUD_TABLA, nodo->correoElectronico, LONGITUD_TABLA, nodo->palabraSecreta, LONGITUD_TABLA, nodo->numeroCuenta, LONGITUD_TABLA, nodo->saldo, LONGITUD_TABLA, nodo->habilitado == ESTADO_HABILITADO ? "Si" : "No");
imprimirLineaSeparadora();
nodo = nodo->siguiente;
}
}
// Lee la lista de clientes y crea el archivo
void guardarLista(struct NodoDeCliente *nodo)
{
FILE *archivo = fopen(NOMBRE_ARCHIVO_CLIENTES, "w");
if (archivo == NULL)
{
printf("No se pudo abrir el archivo\n");
return;
}
while (nodo != NULL)
{
fprintf(archivo, "%s%s%s%s%s%s%s%s%s%s%0.2lf%s%d\n",
nodo->nombre,
DELIMITADOR_CLIENTES,
nodo->identificacion,
DELIMITADOR_CLIENTES,
nodo->correoElectronico,
DELIMITADOR_CLIENTES,
nodo->palabraSecreta,
DELIMITADOR_CLIENTES,
nodo->numeroCuenta,
DELIMITADOR_CLIENTES,
nodo->saldo,
DELIMITADOR_CLIENTES,
nodo->habilitado);
nodo = nodo->siguiente;
}
fclose(archivo);
}
// Lee el archivo de texto y llena la lista de clientes
void recuperarLista(struct NodoDeCliente **nodo)
{
FILE *archivo = fopen(NOMBRE_ARCHIVO_CLIENTES, "r");
if (archivo == NULL)
{
// Fallar silenciosamente, tal vez es la primera ejecución y no hay clientes
return;
}
char bufer[MAXIMA_LONGITUD_CADENA]; // Aquí vamos a ir almacenando cada línea
double saldo = 0;
while (fgets(bufer, MAXIMA_LONGITUD_CADENA, archivo))
{
strtok(bufer, "\n");
char *nombre = strtok(bufer, DELIMITADOR_CLIENTES);
char *identificacion = strtok(NULL, DELIMITADOR_CLIENTES);
char *correoElectronico = strtok(NULL, DELIMITADOR_CLIENTES);
char *palabraSecreta = strtok(NULL, DELIMITADOR_CLIENTES);
char *numeroCuenta = strtok(NULL, DELIMITADOR_CLIENTES);
char *saldoComoCadena = strtok(NULL, DELIMITADOR_CLIENTES);
char *habilitadoComoCadena = strtok(NULL, DELIMITADOR_CLIENTES);
sscanf(saldoComoCadena, "%lf", &saldo);
int habilitado = strtol(habilitadoComoCadena, NULL, 10);
agregarNodoALista(nodo, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, saldo, habilitado);
}
fclose(archivo);
}
int retirarDinero(struct NodoDeCliente *nodo, char *numeroCuenta, double cantidad)
{
while (nodo != NULL)
{
if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
{
if (nodo->saldo >= cantidad)
{
nodo->saldo = nodo->saldo - cantidad;
return 1;
}
else
{
return 0;
}
}
nodo = nodo->siguiente;
}
return 0;
}
int depositarDinero(struct NodoDeCliente *nodo, char *numeroCuenta, double cantidad)
{
return retirarDinero(nodo, numeroCuenta, -cantidad);
}
int transferirDinero(struct NodoDeCliente *nodo, char *cuentaOrigen, char *cuentaDestino, double cantidad)
{
int retiroExitoso = retirarDinero(nodo, cuentaOrigen, cantidad);
if (retiroExitoso)
{
depositarDinero(nodo, cuentaDestino, cantidad);
return 1;
}
else
{
return 0;
}
}
void imprimirDetallesDeCuenta(struct NodoDeCliente *nodo, char *numeroCuenta)
{
while (nodo != NULL)
{
if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
{
printf("Detalles de cuenta\nNumero de cuenta: %s\nSaldo actual: %.2lf\nNombre: %s\n", nodo->numeroCuenta, nodo->saldo, nodo->nombre);
return; // Encontramos al cliente. No necesitamos seguir buscando
}
nodo = nodo->siguiente;
}
printf("Cliente no encontrado\n");
}
void cambiarEstadoHabilitadoDeUsuario(struct NodoDeCliente *nodo, char *numeroCuenta, int nuevoEstado)
{
while (nodo != NULL)
{
if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
{
nodo->habilitado = nuevoEstado;
return;
}
nodo = nodo->siguiente;
}
printf("Usuario no encontrado\n");
}
void deshabilitarUsuario(struct NodoDeCliente *nodo, char *numeroCuenta)
{
cambiarEstadoHabilitadoDeUsuario(nodo, numeroCuenta, ESTADO_DESHABILITADO);
}
void habilitarUsuario(struct NodoDeCliente *nodo, char *numeroCuenta)
{
cambiarEstadoHabilitadoDeUsuario(nodo, numeroCuenta, ESTADO_HABILITADO);
}
int recuperarUsuarioAdministrador(struct Administrador *nodo)
{
FILE *archivo = fopen(NOMBRE_ARCHIVO_ADMINISTRADOR, "r");
if (archivo == NULL)
{
printf("No se pudo leer el archivo del administrador (%s)\n", NOMBRE_ARCHIVO_ADMINISTRADOR);
return 0;
}
char bufer[MAXIMA_LONGITUD_CADENA]; // Aquí vamos a ir almacenando cada línea
if (fgets(bufer, MAXIMA_LONGITUD_CADENA, archivo))
{
strtok(bufer, "\n");
char *correo = strtok(bufer, DELIMITADOR_ADMINISTRADOR);
char *palabraSecreta = strtok(NULL, DELIMITADOR_ADMINISTRADOR);
strcpy(nodo->correo, correo);
strcpy(nodo->palabraSecreta, palabraSecreta);
return 1;
}
else
{
printf("El archivo de datos de administrador existe pero no tiene contenido\n");
return 0;
}
fclose(archivo);
}
void imprimirDetallesAdministrador(struct Administrador *administrador)
{
printf("Correo: '%s'\nPalabra secreta: '%s'\n", administrador->correo, administrador->palabraSecreta);
}
/*
Recibe un apuntador a un apuntador de un NodoDeCliente en donde se desea colocar el usuario logueado, el inicio de la lista de clientes, el correo y la contraseña
Regresa 1 o 0 indicando si el correo y la contraseña coinciden.
Además, en caso de que el inicio de sesión sea correcto pondrá el usuario logueado en usuarioLogueado
*/
int iniciarSesionUsuario(struct NodoDeCliente **usuarioLogueado, struct NodoDeCliente *nodo, char *correoElectronico, char *palabraSecreta)
{
while (nodo != NULL)
{
if (strcmp(nodo->correoElectronico, correoElectronico) == 0 && strcmp(nodo->palabraSecreta, palabraSecreta) == 0)
{
if (nodo->habilitado == ESTADO_DESHABILITADO)
{
printf("Credenciales correctas, pero el usuario esta deshabilitado\n");
return 0;
}
*usuarioLogueado = nodo;
return 1;
}
nodo = nodo->siguiente;
}
return 0;
}
int iniciarSesionAdministrador(struct Administrador **administradorLogueado, struct Administrador *administradorExistente, char *correoElectronico, char *palabraSecreta)
{
if (strcmp(administradorExistente->correo, correoElectronico) == 0 && strcmp(administradorExistente->palabraSecreta, palabraSecreta) == 0)
{
*administradorLogueado = administradorExistente;
return 1;
}
return 0;
}
void leerCadenaYAsegurarseDeQueNoEstaVacia(char destino[MAXIMA_LONGITUD_CADENA], char *mensaje)
{
while (strlen(destino) <= 0)
{
printf("%s", mensaje);
fgets(destino, MAXIMA_LONGITUD_CADENA, stdin);
destino[strcspn(destino, "\r\n")] = 0;
}
}
double leerCantidadYAsegurarseDeQueNoEsNegativa(char *mensaje)
{
double cantidad;
while (1)
{
printf("%s", mensaje);
scanf("%lf", &cantidad);
consumirNuevaLinea();
if (cantidad > 0)
{
return cantidad;
}
else
{
printf("La cantidad debe ser mayor a 0\n");
}
}
return cantidad;
}
int indiceDeCaracterEnCadena(char *cadena, char caracter)
{
int indice = 0;
while (cadena[indice] != '\0')
{
char actual = cadena[indice];
if (actual == caracter)
{
return indice;
}
indice++;
}
return -1;
}
int ultimoIndiceDeCaracterEnCadena(char *cadena, char caracter)
{
int indice = strlen(cadena) - 1;
while (indice >= 0)
{
char actual = cadena[indice];
if (actual == caracter)
{
return indice;
}
indice--;
}
return -1;
}
int esCorreoElectronico(char correo[MAXIMA_LONGITUD_CADENA])
{
int indicePunto = indiceDeCaracterEnCadena(correo, '.');
int indiceArroba = indiceDeCaracterEnCadena(correo, '@');
if (indicePunto == -1 || indiceArroba == -1)
{
return 0;
}
if (indicePunto != ultimoIndiceDeCaracterEnCadena(correo, '.'))
{
return 0;
}
if (indiceArroba != ultimoIndiceDeCaracterEnCadena(correo, '@'))
{
return 0;
}
if (indicePunto < indiceArroba)
{
return 0;
}
return 1;
}
void leerCorreoElectronico(char destino[MAXIMA_LONGITUD_CADENA])
{
while (1)
{
leerCadenaYAsegurarseDeQueNoEstaVacia(destino, "Ingrese el correo electronico: ");
if (esCorreoElectronico(destino))
{
return;
}
else
{
printf("El correo debe contener un . y un @ en la forma example@example.com\n");
strcpy(destino, "");
}
}
}
int contieneAlMenosUnNumero(char cadena[MAXIMA_LONGITUD_CADENA])
{
int indice = 0;
while (cadena[indice] != '\0')
{
char actual = cadena[indice];
if (isdigit(actual))
{
return 1;
}
indice++;
}
return 0;
}
int contieneAlMenosUnaLetra(char cadena[MAXIMA_LONGITUD_CADENA])
{
int indice = 0;
while (cadena[indice] != '\0')
{
char actual = cadena[indice];
if (isalpha(actual))
{
return 1;
}
indice++;
}
return 0;
}
int esPalabraSecretaValida(char palabraSecreta[MAXIMA_LONGITUD_CADENA])
{
if (strlen(palabraSecreta) < 8 || strlen(palabraSecreta) > 12)
{
return 0;
}
if (!contieneAlMenosUnaLetra(palabraSecreta) || !contieneAlMenosUnNumero(palabraSecreta))
{
return 0;
}
return 1;
}
void leerPalabraSecreta(char destino[MAXIMA_LONGITUD_CADENA])
{
while (1)
{
leerCadenaYAsegurarseDeQueNoEstaVacia(destino, "Ingrese la palabra secreta: ");
if (!esPalabraSecretaValida(destino))
{
printf("La palabra secreta debe contener letras, numeros y medir entre 8 y 12 caracteres\n");
strcpy(destino, "");
}
else
{
return;
}
}
}
int aleatorio_en_rango(int minimo, int maximo)
{
return minimo + rand() / (RAND_MAX / (maximo - minimo + 1) + 1);
}
void rellenarCadenaConNumerosAleatorios(char destino[MAXIMA_LONGITUD_CADENA], int cantidadCaracteres)
{
int contador = 0;
static char banco[] = "0123456789";
while (contador < cantidadCaracteres)
{
char aleatorio = banco[aleatorio_en_rango(0, strlen(banco) - 1)];
destino[contador] = aleatorio;
contador++;
}
destino[contador] = '\0';
}
void menuCrearUsuario(struct NodoDeCliente **nodo)
{
char nombre[MAXIMA_LONGITUD_CADENA] = "";
char identificacion[MAXIMA_LONGITUD_CADENA] = "";
char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
leerCadenaYAsegurarseDeQueNoEstaVacia(nombre, "Ingrese el nombre: ");
leerCadenaYAsegurarseDeQueNoEstaVacia(identificacion, "Ingrese la identificacion: ");
leerCorreoElectronico(correoElectronico);
leerPalabraSecreta(palabraSecreta);
rellenarCadenaConNumerosAleatorios(numeroCuenta, CANTIDAD_CIFRAS_NUMERO_CUENTA);
agregarNodoALista(nodo, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, SALDO_POR_DEFECTO, ESTADO_HABILITADO);
}
void menuUsuario(struct NodoDeCliente **apuntadorListaClientes, struct NodoDeCliente *clienteLogueado)
{
int eleccion = 0;
while (eleccion != 5)
{
printf("1. Retirar\n2. Depositar\n3. Transferir\n4. Detalles\n5. Salir\nElige: ");
scanf("%d", &eleccion);
consumirNuevaLinea();
if (eleccion == 1)
{
double cantidad = leerCantidadYAsegurarseDeQueNoEsNegativa("Ingresa la cantidad para retirar: ");
int ok = retirarDinero(*apuntadorListaClientes, clienteLogueado->numeroCuenta, cantidad);
if (ok)
{
printf("Retiro correcto.\n");
imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
}
else
{
printf("Saldo insuficiente\n");
}
}
else if (eleccion == 2)
{
double cantidad = leerCantidadYAsegurarseDeQueNoEsNegativa("Ingresa la cantidad para retirar: ");
int ok = depositarDinero(*apuntadorListaClientes, clienteLogueado->numeroCuenta, cantidad);
if (ok)
{
printf("Deposito correcto.\n");
imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
}
else
{
printf("Error depositando\n");
}
}
else if (eleccion == 3)
{
char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
leerCadenaYAsegurarseDeQueNoEstaVacia(numeroCuenta, "Ingresa el numero de cuenta del beneficiario: ");
double cantidad = leerCantidadYAsegurarseDeQueNoEsNegativa("Ingresa la cantidad para transferir: ");
int ok = transferirDinero(*apuntadorListaClientes, clienteLogueado->numeroCuenta, numeroCuenta, cantidad);
if (ok)
{
printf("Transferencia correcta.\n");
imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
}
else
{
printf("Imposible transferir. Saldo insuficiente o cuenta inexistente\n");
}
}
else if (eleccion == 4)
{
imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
}
}
}
void menuHabilitarODeshabilitar(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administradorLogueado, struct Administrador *administradorExistente)
{
char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
leerCadenaYAsegurarseDeQueNoEstaVacia(numeroCuenta, "Ingresa el numero de cuenta del usuario: ");
int eleccion = 0;
while (eleccion != 3)
{
printf("1. Habilitar\n2. Deshabilitar\n3. Volver\nElige: ");
scanf("%d", &eleccion);
consumirNuevaLinea();
if (eleccion == 1)
{
habilitarUsuario(*apuntadorListaClientes, numeroCuenta);
return;
}
else if (eleccion == 2)
{
deshabilitarUsuario(*apuntadorListaClientes, numeroCuenta);
return;
}
}
}
void menuAdministrador(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administradorLogueado, struct Administrador *administradorExistente)
{
int eleccion = 0;
while (eleccion != 3)
{
printf("1. Listar usuarios\n2. Inhabilitar o habilitar\n3. Salir\nElige: ");
scanf("%d", &eleccion);
consumirNuevaLinea();
if (eleccion == 1)
{
listarUsuarios(*apuntadorListaClientes);
}
else if (eleccion == 2)
{
menuHabilitarODeshabilitar(apuntadorListaClientes, administradorLogueado, administradorExistente);
}
}
}
int menuIngresarUsuario(struct NodoDeCliente **apuntadorListaClientes, struct NodoDeCliente *clienteLogueado)
{
char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
leerCorreoElectronico(correoElectronico);
leerPalabraSecreta(palabraSecreta);
int ok = iniciarSesionUsuario(&clienteLogueado, *apuntadorListaClientes, correoElectronico, palabraSecreta);
if (!ok)
{
printf("Correo o palabra secreta incorrectos\n");
}
else
{
printf("Bienvenido, %s\n", clienteLogueado->nombre);
menuUsuario(apuntadorListaClientes, clienteLogueado);
}
return ok;
}
int menuIngresarAdministrador(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administrador, struct Administrador *administradorExistente)
{
char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
leerCorreoElectronico(correoElectronico);
leerPalabraSecreta(palabraSecreta);
int ok = iniciarSesionAdministrador(&administrador, administradorExistente, correoElectronico, palabraSecreta);
if (!ok)
{
printf("Correo o palabra secreta incorrectos\n");
}
else
{
printf("Bienvenido, %s\n", administrador->correo);
menuAdministrador(apuntadorListaClientes, administrador, administradorExistente);
}
return ok;
}
void menuPrincipal(struct NodoDeCliente **nodo, struct NodoDeCliente *clienteLogueado, struct Administrador *administradorExistente, struct Administrador *administradorLogueado)
{
int eleccion = 0;
while (eleccion != 4)
{
printf("1. Crear usuario\n2. Ingresar usuario\n3. Ingresar administrador\n4. Salir\nElige: ");
scanf("%d", &eleccion);
consumirNuevaLinea();
if (eleccion == 1)
{
menuCrearUsuario(nodo);
}
else if (eleccion == 2)
{
menuIngresarUsuario(nodo, clienteLogueado);
}
else if (eleccion == 3)
{
menuIngresarAdministrador(nodo, administradorLogueado, administradorExistente);
}
}
}
int main()
{
srand(getpid());
struct Administrador *administradorExistente = malloc(sizeof(struct Administrador));
struct Administrador *administradorLogueado = NULL;
struct NodoDeCliente *apuntadorListaClientes = NULL;
struct NodoDeCliente *clienteLogueado = NULL;
if (!recuperarUsuarioAdministrador(administradorExistente))
{
printf("No se pudo recuperar el usuario administrador. Imposible iniciar la aplicacion\n");
return 0;
}
recuperarLista(&apuntadorListaClientes);
menuPrincipal(&apuntadorListaClientes, clienteLogueado, administradorExistente, administradorLogueado);
guardarLista(apuntadorListaClientes);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment