GuinnessServer/commands.c

447 行
13 KiB
C

/*
* commands
* architecture clients/serveur guinness
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
#include "config.h"
#include "defines.h"
#include "xmem.h"
#include "tools.h"
#include "printlog.h"
#include "lists.h"
#include "broadcast.h"
#include "drinks.h"
#include "clients.h"
#include "guinnessd.h"
#include "commands.h"
extern FILE *logfile;
extern int online;
extern char *admin_passwd;
extern char *chemin;
extern Elt *clients_list;
extern Elt *drinks_list;
/* Signification des champs de commandes:
* NOM AIDE ARGS ADM INTRV FCT
*/
cmdslst cmds_srv[] = {
{"help", "cette page d'aide", FALSE, FALSE, FALSE, f_help},
{"quit", "quitter", FALSE, FALSE, FALSE, f_quit},
{"list", "liste des clients connectés", FALSE, FALSE, FALSE, f_list},
{"blist", "liste des boissons disponibles", FALSE, FALSE, FALSE, f_bevr},
{"round", "tournée générale (boisson en option ou préférée)",
TRUE, FALSE, FALSE, f_turn},
{"cold", "la guinness est servie à - de 10°C, sinon entre 12 et 15",
FALSE, FALSE, FALSE, f_cold},
{"msg", "message à tous les clients", TRUE, FALSE, FALSE, f_mesg},
{"infos", "renvoie les infos du serveur", TRUE, FALSE, FALSE, f_info},
{"nick", "change de pseudo", TRUE, FALSE, FALSE, f_nick},
{"123456789", "nombre de verres à recevoir (boisson en option ou "
"préférée)", FALSE, FALSE, TRUE, f_glas},
{"admin", "passer en mode administration", TRUE, FALSE, FALSE, f_sadm},
{"33", "arrêter le serveur", FALSE, TRUE, FALSE, f_shut},
{"add", "ajoute un utilisateur dans la liste des habitués",
TRUE, TRUE, FALSE, f_addu},
{"del", "enlève un utilisateur de la liste des habitués",
TRUE, TRUE, FALSE, f_delu},
{"rldb", "recharge la liste des boissons", FALSE, TRUE, FALSE, f_rldb},
{"save", "sauve la liste des habitués", FALSE, TRUE, FALSE, f_save},
{"load", "charge la liste des habitués", FALSE, TRUE, FALSE, f_load},
{NULL, NULL, FALSE, FALSE, FALSE, NULL}
};
int security_ok (cmdslst cmd, userinfos infos) {
return ( (cmd.adm == FALSE) ||
( (cmd.adm == TRUE) && (infos.admin == TRUE) ) );
}
int reply (int socket_service, char *commande, userinfos *infos) {
int i, cont = TRUE, found = FALSE;
/* Tout d'abord, on remplace \n par \0 ! */
for (i = 0 ; i <= strlen (commande) ; i++)
if ( (commande[i] == '\n') || (commande[i] == '\r') ) {
commande[i] = 0;
}
if (strncmp (commande, "admin ", 6) != 0)
printlog (LOG_NOTIFY, "Commande de %s : [%s] (%d)\n",
infos->nom,
commande,
strlen (commande) );
else {
#ifdef DEBUG
printlog (LOG_NOTIFY, "Commande de %s : [%s]\n", infos->nom, commande);
#else
printlog (LOG_NOTIFY, "Commande de %s : admin XXXXXX\n", infos->nom);
#endif
}
fflush (logfile);
for (i = 0 ; cmds_srv[i].nom != NULL ; i++) {
int cmp = -1;
cmdslst cmd = cmds_srv[i];
if ( (cmd.interv) &&
( (strlen (commande) == 1) ||
(commande[1] == ' ') ) ) {
cmp = strchr (cmd.nom, commande[0]) == NULL ? -1 : 0;
} else {
if (cmd.args)
cmp = strncmp (commande, cmd.nom, strlen (cmd.nom) );
else
cmp = strcmp (commande, cmd.nom);
}
if ( (cmp == 0) && (security_ok (cmd, *infos) == TRUE ) ) {
found = TRUE;
printlog (LOG_NOTIFY, "Commande reconnue : %s\n", cmd.nom);
cont = cmd.fct (socket_service, commande, infos);
break;
}
}
if (! found)
send_infos (socket_service, "Don't flood me with stupidities !\n");
return cont;
}
int send_servercmds (int socket_service) {
char *data;
char cmd[MAXSTRLEN];
int size = 0;
int i;
for (i = 0 ; cmds_srv[i].nom != NULL ; i++) {
memset (cmd, 0, MAXSTRLEN);
if (cmds_srv[i].adm)
snprintf (cmd, MAXSTRLEN - 1, "*%s\n", cmds_srv[i].nom);
else if (cmds_srv[i].interv)
snprintf (cmd, MAXSTRLEN - 1, "+%s\n", cmds_srv[i].nom);
else
snprintf (cmd, MAXSTRLEN - 1, "%s\n", cmds_srv[i].nom);
size += strlen (cmd);
}
data = xmalloc ((size + 1) * sizeof (char));
strcpy (data, "");
for (i = 0 ; cmds_srv[i].nom != NULL ; i++) {
memset (cmd, 0, MAXSTRLEN);
if (cmds_srv[i].adm)
snprintf (cmd, MAXSTRLEN - 1, "*%s\n", cmds_srv[i].nom);
else if (cmds_srv[i].interv)
snprintf (cmd, MAXSTRLEN - 1, "+%s\n", cmds_srv[i].nom);
else
snprintf (cmd, MAXSTRLEN - 1, "%s\n", cmds_srv[i].nom);
strcat (data, cmd);
}
return send_infos (socket_service, data);
}
int f_help (int socket_service, const char *commande, userinfos *infos) {
char *data;
char ligne[MAXSTRLEN];
int size = 0;
int i;
memset (ligne, 0, MAXSTRLEN);
size = strlen ("Commandes (précédées du caractère de commande) :\n");
for (i = 0 ; cmds_srv[i].nom != NULL ; i++) {
if (security_ok (cmds_srv[i], *infos) == TRUE) {
if (cmds_srv[i].args)
snprintf (ligne, MAXSTRLEN - 1, " %s [opts]\t: %s\n",
cmds_srv[i].nom, cmds_srv[i].aide);
else
snprintf (ligne, MAXSTRLEN - 1, " %s%s: %s\n",
cmds_srv[i].nom,
strlen (cmds_srv[i].nom) < 5 ? "\t\t" : "\t",
cmds_srv[i].aide);
size += strlen (ligne);
}
}
data = xmalloc ((size + 1) * sizeof (char));
strcpy (data, "Commandes (précédées du caractère de commande) :\n");
for (i = 0 ; cmds_srv[i].nom != NULL ; i++) {
if (security_ok (cmds_srv[i], *infos) == TRUE) {
if (cmds_srv[i].args)
snprintf (ligne, MAXSTRLEN - 1, " %s [opts]\t: %s\n",
cmds_srv[i].nom, cmds_srv[i].aide);
else
snprintf (ligne, MAXSTRLEN - 1, " %s%s: %s\n",
cmds_srv[i].nom,
strlen (cmds_srv[i].nom) < 5 ? "\t\t" : "\t",
cmds_srv[i].aide);
strcat (data, ligne);
}
}
return send_infos (socket_service, data);
}
int f_quit (int socket_service, const char *commande, userinfos *infos) {
return FALSE;
}
int f_list (int socket_service, const char *commande, userinfos *infos) {
char *data;
int cont;
pthread_mutex_lock (&mutex_clients);
data = list_clients ();
pthread_mutex_unlock (&mutex_clients);
cont = send_infos (socket_service, data);
free (data);
return cont;
}
int f_bevr (int socket_service, const char *commande, userinfos *infos) {
char *data;
int size = 0;
int i;
int cont;
size = strlen ("Boissons disponibles :\n");
for (i = 0 ; i < get_nb_elts (drinks_list) ; i++) {
size += strlen (elt_number (drinks_list, i) );
size += strlen ("\n");
}
data = xmalloc ((size + 1) * sizeof (char));
strcpy (data, "Boissons disponibles :\n");
for (i = 0 ; i < get_nb_elts (drinks_list) ; i++) {
strcat (data, elt_number (drinks_list, i) );
strcat (data, "\n");
}
cont = send_infos (socket_service, data);
free (data);
return cont;
}
int f_cold (int socket_service, const char *commande, userinfos *infos) {
int cont;
if (infos->cold == TRUE) {
infos->cold = FALSE;
cont = send_infos (socket_service, "Température normale.\n");
} else {
infos->cold = TRUE;
cont = send_infos (socket_service, "Température fraîche (10°C).\n");
}
return cont;
}
int f_turn (int socket_service, const char *commande, userinfos *infos) {
int cont = TRUE;
char *breuv = NULL;
if (strlen (commande) > 5) breuv = xstrdup (commande+6);
printlog (LOG_NOTIFY, "Breuvage pour tournée : %s\n",
breuv ? breuv : "préféré");
if ( ( (breuv != NULL) && (exist_elt (drinks_list, breuv) == TRUE) ) ||
(breuv == NULL) ) {
if (! broadcast (TOURNEE, infos->nom, breuv) )
cont = send_infos (socket_service, "Erreur de transmission !\n");
} else
cont = send_infos (socket_service, "Boisson non disponible !\n");
free (breuv);
return cont;
}
int f_mesg (int socket_service, const char *commande, userinfos *infos) {
int cont = TRUE;
if (! broadcast (MESSAGE, infos->nom, commande + 4) )
cont = send_infos (socket_service, "Erreur de transmission !\n");
return cont;
}
int f_info (int socket_service, const char *commande, userinfos *infos) {
int cont = TRUE;
char *data;
if (strlen (commande) == 5) {
data = xmalloc (MAXSTRLEN + 1);
snprintf (data, MAXSTRLEN, "guinnessd - v %s (compilation %s : %s)\n",
VERSION, OS_TYPE, COMPIL_DATE);
} else
data = infos_client (infos->admin, commande + 6);
cont = send_infos (socket_service, data);
free (data);
return cont;
}
int f_nick (int socket_service, const char *commande, userinfos *infos) {
int cont = TRUE, rename_ok;
char *new_nick, *old_nick;
old_nick = xstrdup (infos->nom);
new_nick = xstrdup (commande + 5);
pthread_mutex_lock (&mutex_clients);
rename_ok = rename_client (infos, new_nick);
pthread_mutex_unlock (&mutex_clients);
if (rename_ok) {
char texte[MAXSTRLEN + 1];
snprintf (texte, MAXSTRLEN, "%s s'appelle maintenant %s.\n",
old_nick, new_nick);
if (! broadcast (MESSAGE, NULL, texte) )
cont = send_infos (socket_service, "Erreur de transmission !\n");
} else {
cont = send_infos (socket_service, "Pseudo déjà utilisé !\n");
}
free (old_nick);
free (new_nick);
return cont;
}
int f_glas (int socket_service, const char *commande, userinfos *infos) {
int i, nb, cont = TRUE;
char *breuv;
char *data;
if (strlen (commande) > 2)
breuv = xstrdup (commande + 2);
else
breuv = xstrdup (infos->prefb);
printlog (LOG_NOTIFY, "Breuvage désiré : %s\n", breuv);
data = drinks_get (breuv);
nb = atoi (commande);
for (i = 0 ; i < nb ; i++)
if ( (cont = send_infos (socket_service, data) ) == FALSE) break;
free (data);
free (breuv);
return cont;
}
int f_sadm (int socket_service, const char *commande, userinfos *infos) {
int cont = TRUE;
if ( (admin_passwd) && (strcmp (admin_passwd, commande + 6) == 0) ) {
char message[] = "Vous êtes maintenant ADMINISTRATEUR.\n"
"Nouvelles commandes :";
char *data;
int size = 0, i;
infos->admin = TRUE;
for (i = 0 ; cmds_srv[i].nom != NULL ; i++)
if (cmds_srv[i].adm) size += 1 + strlen (cmds_srv[i].nom);
size += strlen (message);
data = xmalloc ((size + 1) * sizeof (char));
memset (data, 0, size);
strcpy (data, message);
for (i = 0 ; cmds_srv[i].nom != NULL ; i++)
if (cmds_srv[i].adm) {
strcat (data, " ");
strcat (data, cmds_srv[i].nom);
}
cont = send_infos (socket_service, data);
free (data);
} else {
infos->admin = FALSE;
cont = send_infos (socket_service,
"Vous n'êtes PLUS administrateur.\n");
}
return cont;
}
int f_shut (int socket_service, const char *commande, userinfos *infos) {
online = FALSE;
send_infos (socket_service, "Arrêt en cours...\n");
return FALSE;
}
int f_rldb (int socket_service, const char *commande, userinfos *infos) {
free_list (&drinks_list);
add_elt (&drinks_list, "guinness");
if (! chemin) chemin = xstrdup (DRINKS_DIR);
drinks_list_files (chemin);
drinks_display_list ();
return send_infos (socket_service, "Liste des boissons rechargée...\n");
}
int f_addu (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implémentée...\n");
}
int f_delu (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implémentée...\n");
}
int f_save (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implémentée...\n");
}
int f_load (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implémentée...\n");
}