Comment servir des pintes de Guinness "over Internet" ;) Reprise/Fork d'un très ancien code d'un pilier de f.m.b.l : http://tnemeth.free.fr/projets/guinness-server.html
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

guinness.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * guinness
  3. * architecture clients/serveur guinness.
  4. * Thomas Nemeth -- le 15 juin 2001
  5. *
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <getopt.h>
  12. #include <signal.h>
  13. #include <pthread.h>
  14. #include <sys/types.h>
  15. #include <sys/socket.h>
  16. #include <netinet/in.h>
  17. #include <string.h>
  18. #include <strings.h>
  19. #include "defines.h"
  20. #include "xmem.h"
  21. #include "guinness.h"
  22. #include "tools.h"
  23. #include "config.h"
  24. #ifdef SunOS
  25. char *crypt(const char *key, const char *salt);
  26. #else
  27. extern char *crypt __P ((__const char *__key, __const char *__salt));
  28. #endif
  29. /* VARIABLES GLOBALES */
  30. char **commandes = NULL;
  31. char *utilisateur = NULL;
  32. char *boisson = NULL;
  33. char *serveur = NULL;
  34. char *prompt = NULL;
  35. char *logout = NULL;
  36. char cmdchr = 0;
  37. int port = 0;
  38. int nb_cmd = 0;
  39. /*
  40. * Lecture du fichier de config : recuperation des valeurs
  41. *
  42. */
  43. char *get_string_from_token (char *line) {
  44. char *result = line;
  45. char *tmp;
  46. int keyval = 0;
  47. while ( (keyval != 1) && (result [0] != 0) ) {
  48. if (result [0] == '=') keyval = 1;
  49. if (keyval == 0) result++;
  50. }
  51. tmp = result++;
  52. while (tmp [0] != 0) {
  53. if (tmp [0] == '\n') tmp [0] = 0;
  54. tmp++;
  55. }
  56. return result;
  57. }
  58. /*
  59. * Lecture du fichier de config
  60. *
  61. */
  62. void load_config () {
  63. FILE *file;
  64. char *configfile;
  65. char tmpstr[MAXSTRLEN + 1];
  66. char *Home;
  67. char *value;
  68. Home = getenv ("HOME");
  69. configfile = xmalloc ((strlen (Home) +
  70. strlen (CONFIG_FILE) + 2) * sizeof (char));
  71. snprintf (configfile, MAXSTRLEN, "%s/%s", Home, CONFIG_FILE);
  72. /* Ouverture du fichier */
  73. if ( (file = fopen (configfile, "r") ) != NULL) {
  74. /* Lecture du fichier */
  75. while (! feof (file) ) {
  76. memset (tmpstr, 0, MAXSTRLEN + 1);
  77. fgets (tmpstr, (int) MAXSTRLEN, file);
  78. value = get_string_from_token (tmpstr);
  79. if ( (strncmp (tmpstr, "user=", 5) == 0) && (utilisateur == NULL) )
  80. utilisateur = xstrdup (value);
  81. if ( (strncmp (tmpstr, "server=", 7) == 0) && (serveur == NULL) )
  82. serveur = xstrdup (value);
  83. if ( (strncmp (tmpstr, "port=", 5) == 0) && (port == 0) )
  84. port = atoi (value);
  85. if ( (strncmp (tmpstr, "prompt=", 7) == 0) && (prompt == NULL) )
  86. prompt = xstrdup (value);
  87. if ( (strncmp (tmpstr, "pref=", 5) == 0) && (boisson == NULL) )
  88. boisson = xstrdup (value);
  89. if ( (strncmp (tmpstr, "cmdchr=", 7) == 0) && (cmdchr == 0) )
  90. cmdchr = value[0];
  91. if ( (strncmp (tmpstr, "logout=", 7) == 0) && (logout == NULL) )
  92. logout = xstrdup (value);
  93. }
  94. fclose (file);
  95. #ifdef DEBUG
  96. } else {
  97. fprintf (stderr, "Pas de fichier de config (%s).\n", configfile);
  98. #endif
  99. }
  100. free (configfile);
  101. }
  102. /*
  103. * Fonction de nettoyage
  104. *
  105. */
  106. void libere () {
  107. if (utilisateur) free (utilisateur);
  108. if (serveur) free (serveur);
  109. if (boisson) free (boisson);
  110. if (logout) free (logout);
  111. }
  112. /*
  113. * Aide
  114. *
  115. */
  116. void Usage (int help) {
  117. printf ("guinness by Thomas Nemeth - v %s (compilation %s : %s)\n",
  118. VERSION, OS_TYPE, COMPIL_DATE);
  119. if (help)
  120. printf ("Usage : guinness [-h] [-v] [-m machine] "
  121. "[-p port] [-u utilisateur] [-b boisson] [-q msgdx]\n"
  122. " -h : aide sur les parametres\n"
  123. " -v : affiche la version\n"
  124. " -m machine : speficie le nom du serveur\n"
  125. " -p port : specifie le numero du port\n"
  126. " -u utilisateur : nom d'utilisateur\n"
  127. " -b boisson : boisson preferee\n"
  128. " -q msgdx : message d'au-revoir a la deconnexion\n"
  129. " Online (precede du caractere de commande \"/\") :\n"
  130. " help : affiche l'aide sur les commandes\n"
  131. " quit : quitte\n\n");
  132. libere ();
  133. exit (1);
  134. }
  135. /*
  136. * Traitement des arguments
  137. *
  138. */
  139. void traite_argv (int argc, char *argv[]) {
  140. int option;
  141. /* Verification des parametres */
  142. while ((option = getopt (argc, argv, "hvm:p:u:b:q:")) != -1) {
  143. switch (option) {
  144. case 'h' :
  145. Usage (TRUE);
  146. break;
  147. case 'v' :
  148. Usage (FALSE);
  149. break;
  150. case 'm' :
  151. SET_STRING (serveur, optarg);
  152. break;
  153. case 'p' :
  154. port = atoi (optarg);
  155. break;
  156. case 'u' :
  157. SET_STRING (utilisateur, optarg);
  158. break;
  159. case 'b' :
  160. SET_STRING (boisson, optarg);
  161. break;
  162. case 'q' :
  163. SET_STRING (logout, optarg);
  164. break;
  165. default:
  166. Usage (TRUE);
  167. break;
  168. }
  169. }
  170. if (optind < argc) {
  171. if (argc - optind == 1)
  172. fprintf (stderr, "%s: option inconnue --", argv[0]);
  173. else
  174. fprintf (stderr, "%s: options inconnues --", argv[0]);
  175. for ( ; optind < argc ; optind++)
  176. fprintf (stderr, " %s", argv[optind]);
  177. fprintf (stderr, "\n");
  178. Usage (TRUE);
  179. }
  180. }
  181. /*
  182. * Envoi de commande
  183. *
  184. */
  185. int send_cmd (int socket_client) {
  186. char clavier[MAXSTRLEN + 1];
  187. char *commande;
  188. char *admin_crypt;
  189. int i, found = FALSE, cont = TRUE;
  190. /* Lecture d'une commande au clavier */
  191. memset (clavier, 0, MAXSTRLEN);
  192. if ( (fgets (clavier, (int) MAXSTRLEN, stdin) == NULL) &&
  193. feof (stdin) ) {
  194. snprintf (clavier, MAXSTRLEN, "%cquit", cmdchr);
  195. }
  196. /* Determination du type (commande explicite / message) */
  197. if (clavier[0] == cmdchr)
  198. commande = xstrdup (clavier + 1);
  199. else {
  200. commande = xmalloc ((strlen (clavier) + 6) * sizeof (char));
  201. snprintf (commande, strlen (clavier) + 6, "msg %s", clavier);
  202. }
  203. /* Suppression des retours a la ligne pour comparaison */
  204. for (i = 0 ; i < strlen (commande) ; i++)
  205. if (commande[i] == '\n') commande[i] = '\0';
  206. /* Recherche de la bonne commande */
  207. if (strlen (commande) > 0)
  208. for (i = 0 ; i < nb_cmd ; i++) {
  209. int cmp = -1;
  210. if (commandes[i][0] == '*') /* Commandes d'administration */
  211. cmp = strncmp (commandes[i]+1, commande,
  212. strlen (commandes[i])-1);
  213. else if (commandes[i][0] == '+') /* Commandes a intervalle */
  214. cmp = ( (strchr (commandes[i]+1, commande[0]) != NULL) &&
  215. ( (strlen (commande) == 1) ||
  216. (commande[1] == ' ') ) ) ? 0 : -1;
  217. else { /* Commande simple : verification pour la commande entiere
  218. * ou le premier caractere.
  219. */
  220. cmp = (
  221. /* comparaison exacte entre les deux commandes
  222. */
  223. (strncmp (commandes[i], commande,
  224. strlen (commandes[i]) ) == 0) ||
  225. /* comparaison entre les 2 premieres lettres en
  226. * cas de presence de parametres
  227. */
  228. ( (commandes[i][0] == commande[0]) &&
  229. (commande[1] == ' ') ) ||
  230. /* Comparaison entre les deux premieres lettres en cas
  231. * de presence d'une unique lettre dans la commande
  232. */
  233. ( (commandes[i][0] == commande[0]) &&
  234. (strlen (commande) == 1) ) ) ? 0 : -1;
  235. /* Commande trouvee : si un seul caractere, remplacement par
  236. * la commande complete.
  237. */
  238. if ( (cmp == 0) &&
  239. (strncmp (commandes[i], commande,
  240. strlen (commandes[i]) ) != 0) ) {
  241. char *tmpstr;
  242. tmpstr = xmalloc ( (strlen (commande) +
  243. strlen (commandes[i]) ) *
  244. sizeof (char) );
  245. strcpy (tmpstr, commandes[i]);
  246. strcat (tmpstr, commande+1);
  247. #ifdef DEBUG
  248. printf ("Nouvelle commande = %s | %d\n",
  249. tmpstr, strlen (tmpstr) );
  250. #endif
  251. if (strlen (tmpstr) > MAXSTRLEN) {
  252. fprintf (stderr, "Commande trop longue !\n");
  253. printf (prompt);
  254. return TRUE; /* continue */
  255. }
  256. free (commande);
  257. commande = xstrdup (tmpstr);
  258. free (tmpstr);
  259. }
  260. #ifdef DEBUG
  261. printf ("l = %c / c = %c ==> %d\n",
  262. commandes[i][0], commande[0], cmp);
  263. #endif
  264. }
  265. if (cmp == 0) {
  266. #ifdef DEBUG
  267. int j;
  268. printf ("Commande reconnue : %s\n[%s (%d)] :",
  269. commandes[i], commande, strlen (commande) );
  270. for (j = 0 ; j < strlen (commande) ; j++)
  271. printf (" %d", commande[j]);
  272. printf ("\n");
  273. #endif
  274. found = TRUE;
  275. }
  276. }
  277. if (! found) {
  278. #ifdef DEBUG
  279. fprintf (stderr, "Commande inconnue : [%s (%d)]",
  280. commande, strlen (commande) );
  281. for (i = 0 ; i < strlen (commande) ; i++)
  282. fprintf (stderr, " %d", commande[i]);
  283. fprintf (stderr, ".\n\n");
  284. #else
  285. fprintf (stderr, "Commande inconnue : [%s]\n", commande);
  286. #endif
  287. printf (prompt);
  288. return TRUE; /* continue */
  289. }
  290. /* Mode administrateur */
  291. if ( (strncmp (commande, "admin ", 6) == 0) && (strlen (commande) > 6) ) {
  292. int taille;
  293. admin_crypt = xstrdup (crypt (commande + 6, "Gs"));
  294. free (commande);
  295. taille = strlen ("admin ") + strlen (admin_crypt) + 1;
  296. commande = xmalloc (taille);
  297. snprintf (commande, taille, "admin %s", admin_crypt + 2);
  298. }
  299. cont = send_infos (socket_client, commande);
  300. free (commande);
  301. return cont;
  302. }
  303. void set_cmds (char *cmds) {
  304. char *tok, *save;
  305. int i = 0;
  306. #ifdef DEBUG
  307. int j;
  308. #endif
  309. nb_cmd = 0;
  310. save = xstrdup (cmds);
  311. #ifdef DEBUG
  312. printf ("Commandes disponibles : \n");
  313. /* printf ("%s\n", cmds); */
  314. #endif
  315. tok = strtok (save, "\n");
  316. while (tok != NULL) {
  317. nb_cmd++;
  318. tok = strtok (NULL, "\n");
  319. }
  320. commandes = xmalloc ((nb_cmd) * sizeof (char*));
  321. tok = strtok (cmds, "\n");
  322. while (tok != NULL) {
  323. commandes[i] = xstrdup (tok);
  324. #ifdef DEBUG
  325. if (tok[0] == '+') {
  326. for (j = 1 ; j < strlen (commandes[i]) ; j++)
  327. printf ("%c%c ", cmdchr, commandes[i][j]);
  328. } else if (tok[0] != '*') {
  329. printf ("%c%s ", cmdchr, commandes[i]);
  330. }
  331. #endif
  332. i++;
  333. tok = strtok (NULL, "\n");
  334. }
  335. printf ("\n");
  336. free (save);
  337. }
  338. /*
  339. * Fonction d'initialisation de la communication
  340. *
  341. */
  342. int initiate (int socket_client) {
  343. char cmds[MAXSTRLEN];
  344. char datas[MAXSTRLEN];
  345. char nick_ok[MAXSTRLEN];
  346. int cont = TRUE;
  347. memset (datas, 0, MAXSTRLEN);
  348. /* Reception de la liste des commandes */
  349. cont = read_infos (socket_client, cmds);
  350. if (cont) {
  351. set_cmds (cmds);
  352. snprintf (datas, MAXSTRLEN - 1, "%s\n%s\n%s",
  353. utilisateur, boisson, logout);
  354. /* Envoi des donnees utilisateur */
  355. cont = send_infos (socket_client, datas);
  356. read_infos (socket_client, nick_ok);
  357. if (nick_ok[0] == '@') {
  358. printf ("%s", nick_ok + 1);
  359. return FALSE;
  360. }
  361. printf ("%s", nick_ok);
  362. /* Traitement des commandes et des infos */
  363. printf (prompt);
  364. }
  365. return cont;
  366. }
  367. /*
  368. * Boucle de commande et de reception
  369. *
  370. */
  371. void data_rw (int socket_client) {
  372. int cont = TRUE;
  373. char infos[MAXSTRLEN];
  374. fd_set lire;
  375. cont = initiate (socket_client);
  376. while (cont == TRUE) {
  377. fflush (stdout);
  378. /* Construction de l'ensemble a scruter en lecture : */
  379. FD_ZERO (&lire);
  380. FD_SET (STDIN_FILENO, &lire);
  381. FD_SET (socket_client, &lire);
  382. /* Attente d'un message sur la liste : */
  383. select (socket_client + 1, &lire, NULL, NULL, NULL);
  384. if (FD_ISSET (STDIN_FILENO, &lire) ) {
  385. cont = send_cmd (socket_client);
  386. } else {
  387. int is;
  388. cont = read_infos (socket_client, infos);
  389. is = 0;
  390. do {
  391. printf ("%s\n", infos + is);
  392. while (is < MAXSTRLEN && infos[is]) is ++;
  393. /* on suppose qu'un seul '\0' separe deux messages */
  394. is ++;
  395. } while (is < MAXSTRLEN && infos[is]);
  396. /* Hack pour faire afficher le message par xmessage
  397. * Pas tres joli lors des deconnexions.
  398. */
  399. /* if (getenv ("DISPLAY")) { */
  400. /* if (! fork ()) */
  401. /* execlp ("xmessage", "xmessage", infos, NULL); */
  402. /* } */
  403. fflush (stdout);
  404. printf (prompt);
  405. }
  406. }
  407. printf ("%s\n", logout);
  408. close (socket_client);
  409. }
  410. /*
  411. * Gestionnaire de signal SIGPIPE
  412. *
  413. */
  414. void handler_sigpipe (int sig) {
  415. printf ("Signal SIGPIPE recu...\n");
  416. }
  417. /*
  418. * Fonction principale
  419. *
  420. */
  421. int main (int argc, char *argv[]) {
  422. int socket_client;
  423. char *environ_user;
  424. signal (SIGPIPE, handler_sigpipe);
  425. /* Verification des parametres */
  426. traite_argv (argc, argv);
  427. /* Lecture du fichier de config */
  428. load_config ();
  429. /* Valeurs par defaut */
  430. if (! utilisateur) {
  431. environ_user = getenv ("USER");
  432. if (environ_user && *environ_user)
  433. utilisateur = xstrdup (environ_user);
  434. else
  435. utilisateur = xstrdup ("toto");
  436. }
  437. if (IS_NOT_GOOD (serveur)) SET_STRING (serveur, DEFAULT_SERVER);
  438. if (IS_NOT_GOOD (prompt)) SET_STRING (prompt, DEFAULT_PROMPT);
  439. if (IS_NOT_GOOD (boisson)) SET_STRING (boisson, DEFAULT_DRINK);
  440. if (IS_NOT_GOOD (logout)) SET_STRING (logout, DEFAULT_LOGOUT);
  441. if (cmdchr == 0) cmdchr = '/';
  442. if (port == 0) port = DEFAULT_SERVER_PORT;
  443. printf ("Serveur : [%s]\t", serveur);
  444. printf ("Port : [%d]\n", port);
  445. printf ("Utilisateur : [%s]\t", utilisateur);
  446. printf ("\tBoisson : [%s]\t", boisson);
  447. printf ("Logout : [%s]\n", logout);
  448. printf ("Prefixe : [%c]\n", cmdchr);
  449. /* Connexion au serveur */
  450. if ( (socket_client = connect_server (serveur, port) ) == -1) {
  451. fprintf (stderr, "Connexion refusee...\n");
  452. return -1;
  453. }
  454. printf ("-+- Connexion acceptee. -+-\n");
  455. data_rw (socket_client);
  456. libere ();
  457. return 0;
  458. }