/* * guinness * architecture clients/serveur guinness. * Thomas Nemeth -- le 15 juin 2001 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "xmem.h" #include "guinness.h" #include "tools.h" #include "config.h" #ifdef SunOS char *crypt(const char *key, const char *salt); #else extern char *crypt __P ((__const char *__key, __const char *__salt)); #endif /* VARIABLES GLOBALES */ char **commandes = NULL; char *utilisateur = NULL; char *boisson = NULL; char *serveur = NULL; char *prompt = NULL; char *logout = NULL; char cmdchr = 0; int port = 0; int nb_cmd = 0; /* * Lecture du fichier de config : recuperation des valeurs * */ char *get_string_from_token (char *line) { char *result = line; char *tmp; int keyval = 0; while ( (keyval != 1) && (result [0] != 0) ) { if (result [0] == '=') keyval = 1; if (keyval == 0) result++; } tmp = result++; while (tmp [0] != 0) { if (tmp [0] == '\n') tmp [0] = 0; tmp++; } return result; } /* * Lecture du fichier de config * */ void load_config () { FILE *file; char *configfile; char tmpstr[MAXSTRLEN + 1]; char *Home; char *value; Home = getenv ("HOME"); configfile = xmalloc ((strlen (Home) + strlen (CONFIG_FILE) + 2) * sizeof (char)); snprintf (configfile, MAXSTRLEN, "%s/%s", Home, CONFIG_FILE); /* Ouverture du fichier */ if ( (file = fopen (configfile, "r") ) != NULL) { /* Lecture du fichier */ while (! feof (file) ) { memset (tmpstr, 0, MAXSTRLEN + 1); fgets (tmpstr, (int) MAXSTRLEN, file); value = get_string_from_token (tmpstr); if ( (strncmp (tmpstr, "user=", 5) == 0) && (utilisateur == NULL) ) utilisateur = xstrdup (value); if ( (strncmp (tmpstr, "server=", 7) == 0) && (serveur == NULL) ) serveur = xstrdup (value); if ( (strncmp (tmpstr, "port=", 5) == 0) && (port == 0) ) port = atoi (value); if ( (strncmp (tmpstr, "prompt=", 7) == 0) && (prompt == NULL) ) prompt = xstrdup (value); if ( (strncmp (tmpstr, "pref=", 5) == 0) && (boisson == NULL) ) boisson = xstrdup (value); if ( (strncmp (tmpstr, "cmdchr=", 7) == 0) && (cmdchr == 0) ) cmdchr = value[0]; if ( (strncmp (tmpstr, "logout=", 7) == 0) && (logout == NULL) ) logout = xstrdup (value); } fclose (file); #ifdef DEBUG } else { fprintf (stderr, "Pas de fichier de config (%s).\n", configfile); #endif } free (configfile); } /* * Fonction de nettoyage * */ void libere () { if (utilisateur) free (utilisateur); if (serveur) free (serveur); if (boisson) free (boisson); if (logout) free (logout); } /* * Aide * */ void Usage (int help) { printf ("guinness by Thomas Nemeth - v %s (compilation %s : %s)\n", VERSION, OS_TYPE, COMPIL_DATE); if (help) printf ("Usage : guinness [-h] [-v] [-m machine] " "[-p port] [-u utilisateur] [-b boisson] [-q msgdx]\n" " -h : aide sur les parametres\n" " -v : affiche la version\n" " -m machine : speficie le nom du serveur\n" " -p port : specifie le numero du port\n" " -u utilisateur : nom d'utilisateur\n" " -b boisson : boisson preferee\n" " -q msgdx : message d'au-revoir a la deconnexion\n" " Online (precede du caractere de commande \"/\") :\n" " help : affiche l'aide sur les commandes\n" " quit : quitte\n\n"); libere (); exit (1); } /* * Traitement des arguments * */ void traite_argv (int argc, char *argv[]) { int option; /* Verification des parametres */ while ((option = getopt (argc, argv, "hvm:p:u:b:q:")) != -1) { switch (option) { case 'h' : Usage (TRUE); break; case 'v' : Usage (FALSE); break; case 'm' : SET_STRING (serveur, optarg); break; case 'p' : port = atoi (optarg); break; case 'u' : SET_STRING (utilisateur, optarg); break; case 'b' : SET_STRING (boisson, optarg); break; case 'q' : SET_STRING (logout, optarg); break; default: Usage (TRUE); break; } } if (optind < argc) { if (argc - optind == 1) fprintf (stderr, "%s: option inconnue --", argv[0]); else fprintf (stderr, "%s: options inconnues --", argv[0]); for ( ; optind < argc ; optind++) fprintf (stderr, " %s", argv[optind]); fprintf (stderr, "\n"); Usage (TRUE); } } /* * Envoi de commande * */ int send_cmd (int socket_client) { char clavier[MAXSTRLEN + 1]; char *commande; char *admin_crypt; int i, found = FALSE, cont = TRUE; /* Lecture d'une commande au clavier */ memset (clavier, 0, MAXSTRLEN); if ( (fgets (clavier, (int) MAXSTRLEN, stdin) == NULL) && feof (stdin) ) { snprintf (clavier, MAXSTRLEN, "%cquit", cmdchr); } /* Determination du type (commande explicite / message) */ if (clavier[0] == cmdchr) commande = xstrdup (clavier + 1); else { commande = xmalloc ((strlen (clavier) + 6) * sizeof (char)); snprintf (commande, strlen (clavier) + 6, "msg %s", clavier); } /* Suppression des retours a la ligne pour comparaison */ for (i = 0 ; i < strlen (commande) ; i++) if (commande[i] == '\n') commande[i] = '\0'; /* Recherche de la bonne commande */ if (strlen (commande) > 0) for (i = 0 ; i < nb_cmd ; i++) { int cmp = -1; if (commandes[i][0] == '*') /* Commandes d'administration */ cmp = strncmp (commandes[i]+1, commande, strlen (commandes[i])-1); else if (commandes[i][0] == '+') /* Commandes a intervalle */ cmp = ( (strchr (commandes[i]+1, commande[0]) != NULL) && ( (strlen (commande) == 1) || (commande[1] == ' ') ) ) ? 0 : -1; else { /* Commande simple : verification pour la commande entiere * ou le premier caractere. */ cmp = ( /* comparaison exacte entre les deux commandes */ (strncmp (commandes[i], commande, strlen (commandes[i]) ) == 0) || /* comparaison entre les 2 premieres lettres en * cas de presence de parametres */ ( (commandes[i][0] == commande[0]) && (commande[1] == ' ') ) || /* Comparaison entre les deux premieres lettres en cas * de presence d'une unique lettre dans la commande */ ( (commandes[i][0] == commande[0]) && (strlen (commande) == 1) ) ) ? 0 : -1; /* Commande trouvee : si un seul caractere, remplacement par * la commande complete. */ if ( (cmp == 0) && (strncmp (commandes[i], commande, strlen (commandes[i]) ) != 0) ) { char *tmpstr; tmpstr = xmalloc ( (strlen (commande) + strlen (commandes[i]) ) * sizeof (char) ); strcpy (tmpstr, commandes[i]); strcat (tmpstr, commande+1); #ifdef DEBUG printf ("Nouvelle commande = %s | %d\n", tmpstr, strlen (tmpstr) ); #endif if (strlen (tmpstr) > MAXSTRLEN) { fprintf (stderr, "Commande trop longue !\n"); printf (prompt); return TRUE; /* continue */ } free (commande); commande = xstrdup (tmpstr); free (tmpstr); } #ifdef DEBUG printf ("l = %c / c = %c ==> %d\n", commandes[i][0], commande[0], cmp); #endif } if (cmp == 0) { #ifdef DEBUG int j; printf ("Commande reconnue : %s\n[%s (%d)] :", commandes[i], commande, strlen (commande) ); for (j = 0 ; j < strlen (commande) ; j++) printf (" %d", commande[j]); printf ("\n"); #endif found = TRUE; } } if (! found) { #ifdef DEBUG fprintf (stderr, "Commande inconnue : [%s (%d)]", commande, strlen (commande) ); for (i = 0 ; i < strlen (commande) ; i++) fprintf (stderr, " %d", commande[i]); fprintf (stderr, ".\n\n"); #else fprintf (stderr, "Commande inconnue : [%s]\n", commande); #endif printf (prompt); return TRUE; /* continue */ } /* Mode administrateur */ if ( (strncmp (commande, "admin ", 6) == 0) && (strlen (commande) > 6) ) { int taille; admin_crypt = xstrdup (crypt (commande + 6, "Gs")); free (commande); taille = strlen ("admin ") + strlen (admin_crypt) + 1; commande = xmalloc (taille); snprintf (commande, taille, "admin %s", admin_crypt + 2); } cont = send_infos (socket_client, commande); free (commande); return cont; } void set_cmds (char *cmds) { char *tok, *save; int i = 0; #ifdef DEBUG int j; #endif nb_cmd = 0; save = xstrdup (cmds); #ifdef DEBUG printf ("Commandes disponibles : \n"); /* printf ("%s\n", cmds); */ #endif tok = strtok (save, "\n"); while (tok != NULL) { nb_cmd++; tok = strtok (NULL, "\n"); } commandes = xmalloc ((nb_cmd) * sizeof (char*)); tok = strtok (cmds, "\n"); while (tok != NULL) { commandes[i] = xstrdup (tok); #ifdef DEBUG if (tok[0] == '+') { for (j = 1 ; j < strlen (commandes[i]) ; j++) printf ("%c%c ", cmdchr, commandes[i][j]); } else if (tok[0] != '*') { printf ("%c%s ", cmdchr, commandes[i]); } #endif i++; tok = strtok (NULL, "\n"); } printf ("\n"); free (save); } /* * Fonction d'initialisation de la communication * */ int initiate (int socket_client) { char cmds[MAXSTRLEN]; char datas[MAXSTRLEN]; char nick_ok[MAXSTRLEN]; int cont = TRUE; memset (datas, 0, MAXSTRLEN); /* Reception de la liste des commandes */ cont = read_infos (socket_client, cmds); if (cont) { set_cmds (cmds); snprintf (datas, MAXSTRLEN - 1, "%s\n%s\n%s", utilisateur, boisson, logout); /* Envoi des donnees utilisateur */ cont = send_infos (socket_client, datas); read_infos (socket_client, nick_ok); if (nick_ok[0] == '@') { printf ("%s", nick_ok + 1); return FALSE; } printf ("%s", nick_ok); /* Traitement des commandes et des infos */ printf (prompt); } return cont; } /* * Boucle de commande et de reception * */ void data_rw (int socket_client) { int cont = TRUE; char infos[MAXSTRLEN]; fd_set lire; cont = initiate (socket_client); while (cont == TRUE) { fflush (stdout); /* Construction de l'ensemble a scruter en lecture : */ FD_ZERO (&lire); FD_SET (STDIN_FILENO, &lire); FD_SET (socket_client, &lire); /* Attente d'un message sur la liste : */ select (socket_client + 1, &lire, NULL, NULL, NULL); if (FD_ISSET (STDIN_FILENO, &lire) ) { cont = send_cmd (socket_client); } else { int is; cont = read_infos (socket_client, infos); is = 0; do { printf ("%s\n", infos + is); while (is < MAXSTRLEN && infos[is]) is ++; /* on suppose qu'un seul '\0' separe deux messages */ is ++; } while (is < MAXSTRLEN && infos[is]); /* Hack pour faire afficher le message par xmessage * Pas tres joli lors des deconnexions. */ /* if (getenv ("DISPLAY")) { */ /* if (! fork ()) */ /* execlp ("xmessage", "xmessage", infos, NULL); */ /* } */ fflush (stdout); printf (prompt); } } printf ("%s\n", logout); close (socket_client); } /* * Gestionnaire de signal SIGPIPE * */ void handler_sigpipe (int sig) { printf ("Signal SIGPIPE recu...\n"); } /* * Fonction principale * */ int main (int argc, char *argv[]) { int socket_client; char *environ_user; signal (SIGPIPE, handler_sigpipe); /* Verification des parametres */ traite_argv (argc, argv); /* Lecture du fichier de config */ load_config (); /* Valeurs par defaut */ if (! utilisateur) { environ_user = getenv ("USER"); if (environ_user && *environ_user) utilisateur = xstrdup (environ_user); else utilisateur = xstrdup ("toto"); } if (IS_NOT_GOOD (serveur)) SET_STRING (serveur, DEFAULT_SERVER); if (IS_NOT_GOOD (prompt)) SET_STRING (prompt, DEFAULT_PROMPT); if (IS_NOT_GOOD (boisson)) SET_STRING (boisson, DEFAULT_DRINK); if (IS_NOT_GOOD (logout)) SET_STRING (logout, DEFAULT_LOGOUT); if (cmdchr == 0) cmdchr = '/'; if (port == 0) port = DEFAULT_SERVER_PORT; printf ("Serveur : [%s]\t", serveur); printf ("Port : [%d]\n", port); printf ("Utilisateur : [%s]\t", utilisateur); printf ("\tBoisson : [%s]\t", boisson); printf ("Logout : [%s]\n", logout); printf ("Prefixe : [%c]\n", cmdchr); /* Connexion au serveur */ if ( (socket_client = connect_server (serveur, port) ) == -1) { fprintf (stderr, "Connexion refusee...\n"); return -1; } printf ("-+- Connexion acceptee. -+-\n"); data_rw (socket_client); libere (); return 0; }