1 /*
2  * Copyright (C) 1993 Andrew Scherpbier (Andrew@sdsu.edu)
3  *
4  * This file is part of xpmtp.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "xpmtp.h"
27 
28 typedef struct
29 {
30 	char	*name;
31 	int		min_args;
32 	int		max_args;
33 #ifdef __STDC__
34 	void	(*func)(int argc, char **argv);
35 #else
36 	void	(*func)();
37 #endif
38 	char	*shorthelp;
39 	char	*longhelp;
40 } COMMAND;
41 
42 #ifdef __STDC__
43 void	command_help(int argc, char **argv);
44 void	command_send(int argc, char **argv);
45 void	command_quit(int argc, char **argv);
46 void	command_put(int argc, char **argv);
47 void	command_get(int argc, char **argv);
48 void	command_geti(int argc, char **argv);
49 void	command_unknown(int argc, char **argv);
50 void	command_wildmap(int argc, char **argv);
51 void	argv_to_command(char **argv);
52 int		connected();
53 void	done(int exit_value);
54 void	usage();
55 #else
56 void	command_help(/* int argc, char **argv */);
57 void	command_send(/* int argc, char **argv */);
58 void	command_quit(/* int argc, char **argv */);
59 void	command_put(/* int argc, char **argv */);
60 void	command_get(/* int argc, char **argv */);
61 void	command_geti(/* int argc, char **argv */);
62 void	command_unknown(/* int argc, char **argv */);
63 void	command_wildmap(/* int argc, char **argv */);
64 void	argv_to_command(/* char **argv */);
65 int		connected();
66 void	done(/* int exit_value */);
67 void	usage();
68 #endif
69 
70 COMMAND	commands[] =
71 {
72 	"help",		0,	XPMTP_MAX_ARGS,	command_help,	"Display this list of commands.  HELP HELP will give more info",
73 "usage: help [command]\n\
74 Without the command argument, the HELP command will list all available commmands\n\
75 with a short description.  By specifying the command, you get more detailed help",
76 	"quit",		0,	0,				command_quit,	"Quit the connection with the server",
77 "usage: quit\n\
78 This will close the connection with the map server and quit the client program.",
79 	"get",		1,	2,				command_get,	"Get a map",
80 "usage: get mapname [localmapname]\n\
81 This is used to retrieve a map from the map server.  The optional localmapname\n\
82 specifies the name you want the map to have on your system.",
83 	"geti",		1,	2,				command_geti,	"Get a PBM image of a map.",
84 "usage: geti mapname [localpbmfilename]\n\
85 Use this to retrieve a small (64x64) pbm image representation of the specified\n\
86 map.  If no localpbmfilename is specified, the mapname is used with the .map\n\
87 substitued with .pbm",
88 	"submit",	1,	2,				command_put,	"Submit a map to the server for others to use",
89 "usage: submit localmapname [remotemapname]\n\
90 Send a map to the map server.  The localmapname is the name you use on your\n\
91 system. If you don't specify a remote map name, the local map name will be used.\n\
92 Note that you CANNOT overwrite an existing map.  If you feel you need to\n\
93 replace a map, contact the map server maintainer.  (See the maintainer command)",
94 	"list",		0,	2,				command_send,	"List the currently available maps.",
95 "usage: list [-l] [mapname]\n\
96 List one or all maps in the archive.  If mapname is specified, only that map is\n\
97 listed.  If the -l option is specified, more information about each map is\n\
98 returned.  The fields in this long list are tab seperated so they are easy to\n\
99 parse with a program.",
100 	"display",	1,	3,				command_send,	"Display image of map in a X window.",
101 "usage: display [-display machine:0.0] mapname\n\
102 Create an X window on the specified display.  If no display is explicitly\n\
103 specified the machine you are connecting from will be used.\n\
104 The image displayed is a small (128x128) image representation of the specified\n\
105 map.  This gives you a quick overview of what the map looks like.  Remember\n\
106 that ALL maps are displayed in the same size.  The aspect ratio is preserved,\n\
107 however.",
108 	"wildmap",	0,	XPMTP_MAX_ARGS,	command_wildmap,"Generate a random map using the 'wildmap' program and get it.",
109 "usage: wildmap [-options] [localmapname]\n\
110 This will create a random map using the wildmap command.  To get a list of the\n\
111 options to the wildmap program, use the 'wildmap -help' command.\n\
112 If no localmapname is specified, wildmap.map is used.",
113 	"maintainer",0,	0,				command_send,	"Show how to get in touch with the maintainer",
114 "usage: maintainer\n\
115 Show how to get in touch with the map server maintainer.\n\
116 You should contact this person if you are having problems of if you want to\n\
117 update/replace an existing map.  (You are not allowed to do that using XPMTP)",
118 };
119 
120 
121 #define NCOMMANDS	(sizeof(commands)/sizeof(COMMAND))
122 
123 int		xpmtp_fd = -1;
124 char	xpmtp_buf[4096];
125 char	command[XPMTP_MAX_LINE];
126 char	response[XPMTP_MAX_LINE];
127 
128 extern int	optind;
129 extern char	*optarg;
130 
131 #ifdef __STDC__
main(int argc,char ** argv)132 main(int argc, char **argv)
133 #else
134 main(argc, argv)
135 int		argc;
136 char	**argv;
137 #endif
138 {
139 	char	buf[256];
140 	int		i;
141 	int		port = XPMTP_PORT;
142 	int		c;
143 	char	*av[XPMTP_MAX_ARGS], *p, *host = NULL;
144 	int		ac, first;
145 
146 	while ((c = getopt(argc, argv, "h:p:")) != -1)
147 	{
148 		switch (c)
149 		{
150 			case 'h':
151 				host = optarg;
152 				break;
153 			case 'p':
154 				port = atoi(optarg);
155 				break;
156 			case '?':
157 				usage();
158 				done(0);
159 		}
160 	}
161 
162 	if (optind != argc)
163 	{
164 		usage();
165 		done(1);
166 	}
167 
168 	if (host == NULL)
169 	{
170 		host = xpmtp_default_host();
171 	}
172 
173 	printf("Opening XPMTP connection with %s ...\n", host);
174 	xpmtp_fd = xpmtp_open(host, port, response, sizeof(response));
175 	if (xpmtp_fd < 0)
176 	{
177 		xpmtp_perror("open");
178 		done(1);
179 	}
180 	else
181 	{
182 		printf("Connected to %s port %d.\n", host, port);
183 		printf("%s\n", response+1);
184 	}
185 
186 	for (;;)
187 	{
188 		printf("xpmtp> ");
189 		fflush(stdout);
190 		if (fgets(buf, sizeof(buf), stdin) == NULL)
191 		{
192 			command_quit(ac, av);
193 		}
194 		first = 1;
195 		ac = 0;
196 		while (p = strtok(first ? buf : NULL, " \t\r\n"))
197 		{
198 			av[ac++] = p;
199 			first = 0;
200 		}
201 		av[ac] = NULL;
202 
203 		if (av[0] == NULL)
204 		{
205 			continue;
206 		}
207 
208 		for (i = 0; i < NCOMMANDS; i++)
209 		{
210 			if (strcasecmp(commands[i].name, av[0]) == 0)
211 			{
212 				if (commands[i].min_args >= 0 && ac-1 < commands[i].min_args
213 					|| commands[i].max_args >= 0 && ac-1 > commands[i].max_args)
214 				{
215 					printf("wrong number of arguments.\n");
216 				}
217 				else
218 				{
219 					(*commands[i].func)(ac, av);
220 				}
221 				break;
222 			}
223 		}
224 		if (i == NCOMMANDS)
225 		{
226 			command_unknown(ac, av);
227 		}
228 	}
229 }
230 
231 #ifdef __STDC__
argv_to_command(char ** argv)232 void	argv_to_command(char **argv)
233 #else
234 void	argv_to_command(argv)
235 char	**argv;
236 #endif
237 {
238 	command[0] = '\0';
239 	for (; *argv; argv++)
240 	{
241 		strcat(command, *argv);
242 		if (*(argv+1))
243 		{
244 			strcat(command, " ");
245 		}
246 	}
247 }
248 
249 #ifdef __STDC__
command_quit(int argc,char ** argv)250 void	command_quit(int argc, char **argv)
251 #else
252 void	command_quit(argc, argv)
253 int	argc;
254 char	**argv;
255 #endif
256 {
257 	if (xpmtp_fd != -1)
258 	{
259 		xpmtp_close(xpmtp_fd);
260 		printf("Connection closed.\n");
261 	}
262 	done(0);
263 }
264 
265 #ifdef __STDC__
command_help(int argc,char ** argv)266 void	command_help(int argc, char **argv)
267 #else
268 void	command_help(argc, argv)
269 int	argc;
270 char	**argv;
271 #endif
272 {
273 	int		i;
274 	int		j;
275 	int		found;
276 
277 	if (argc == 1)
278 	{
279 		/*
280 		 * Short list
281 		 */
282 		for (i = 0; i < NCOMMANDS; i++)
283 			printf("%7s -- %s\n\n", commands[i].name, commands[i].shorthelp);
284 	}
285 	else
286 	{
287 		for (j = 1; j < argc; j++)
288 		{
289 			found = 0;
290 			for (i = 0; i < NCOMMANDS; i++)
291 			{
292 				if (strcmp(commands[i].name, argv[j]) == 0)
293 				{
294 					printf("%7s -- %s\n", commands[i].name, commands[i].shorthelp);
295 					printf("%s\n\n", commands[i].longhelp);
296 					found = 1;
297 					break;
298 				}
299 			}
300 			if (!found)
301 				printf("ERR Sorry, '%s' is not a recognized command\n", argv[j]);
302 		}
303 	}
304 }
305 
306 #ifdef __STDC__
command_put(int argc,char ** argv)307 void	command_put(int argc, char **argv)
308 #else
309 void	command_put(argc, argv)
310 int	argc;
311 char	**argv;
312 #endif
313 {
314 	FILE		*fp;
315 	char		*filename;
316 	char		*remotefilename;
317 	char		buffer[1024];
318 	int			n;
319 	struct stat	buf;
320 
321 	if (argc == 3)
322 		remotefilename = argv[2];
323 	else
324 		remotefilename = argv[1];
325 	filename = argv[1];
326 
327 	/*
328 	 * Make sure that we aren't kidding about sending a map.  We need to first
329 	 * make sure that it really exists locally.
330 	 */
331 	if (stat(filename, &buf) == -1)
332 	{
333 		printf("ERR: You are trying to send a file which does not exist!\n");
334 		return;
335 	}
336 	fp = fopen(filename, "r");
337 	if (fp == NULL)
338 	{
339 		printf("ERR: Unable to open %s for reading.\n", filename);
340 		return;
341 	}
342 
343 	argv[1] = remotefilename;
344 	argv[2] = NULL;
345 	argv_to_command(argv);
346 
347 	switch (xpmtp_command(xpmtp_fd, command, response, sizeof(response)))
348 	{
349 		case -1:
350 			xpmtp_perror(argv[0]);
351 			command_quit(argc, argv);
352 			return;
353 		default:
354 			if (*response == '-')
355 			{
356 				printf("%s\n", response+1);
357 				return;
358 			}
359 	}
360 
361 	/*
362 	 * We are now ready to send the map over.
363 	 * First the size, then the map, just like the server were to send a map to
364 	 * us.
365 	 */
366 	xpmtp_putline(xpmtp_fd, "#%d", buf.st_size);
367 
368 	n = 1;
369 	while (n > 0)
370 	{
371 		n = fread(buffer, 1, 1024, fp);
372 		if (n == 0)
373 			break;				/* All done writing */
374 		n = xpmtp_write(xpmtp_fd, buffer, n);
375 		if (n <= 0)
376 		{
377 			/*
378 			 * Some problem arized!
379 			 */
380 			printf("ERR: Hmmm...  Problems writing\n");
381 			return;
382 		}
383 	}
384 
385 	fclose(fp);
386 	printf("OK Submitted map '%s'\n", remotefilename);
387 }
388 
389 #ifdef __STDC__
command_get(int argc,char ** argv)390 void	command_get(int argc, char **argv)
391 #else
392 void	command_get(argc, argv)
393 int	argc;
394 char	**argv;
395 #endif
396 {
397 	FILE	*fp;
398 	char	*filename;
399 	char	*p;
400 	int	size, n, nread;
401 	char	cmd[100];
402 
403 	if (argc == 3)
404 	{
405 		filename = argv[2];
406 		argv[2] = NULL;
407 	}
408 	else
409 	{
410 		filename = argv[1];
411 	}
412 
413 	argv_to_command(argv);
414 
415 	switch (xpmtp_command(xpmtp_fd, command, response, sizeof(response)))
416 	{
417 		case -1:
418 			xpmtp_perror(argv[0]);
419 			command_quit(argc, argv);
420 			return;
421 		default:
422 			if (*response == '-')
423 			{
424 				printf("%s\n", response+1);
425 				return;
426 			}
427 	}
428 
429 	size = atoi(response + 1);
430 
431 	fp = fopen(filename, "w");
432 	if (fp == NULL)
433 	{
434 		perror(filename);
435 		return;
436 	}
437 
438 	while (size > 0)
439 	{
440 		n = MIN(sizeof(xpmtp_buf), size);
441 		nread = xpmtp_read(xpmtp_fd, xpmtp_buf, n);
442 		if (nread != n)
443 		{
444 			xpmtp_perror("get");
445 			break;
446 		}
447 		fwrite(xpmtp_buf, 1, n, fp);
448 		size -= n;
449 	}
450 
451 	fclose(fp);
452 	printf("OK Retrieved map:\n");
453 	sprintf(cmd, "ls -l %s", filename);
454 	system(cmd);
455 }
456 
457 #ifdef __STDC__
command_geti(int argc,char ** argv)458 void	command_geti(int argc, char **argv)
459 #else
460 void	command_geti(argc, argv)
461 int	argc;
462 char	**argv;
463 #endif
464 {
465 	FILE	*fp;
466 	char	*filename;
467 	char	*p;
468 	int		size, n, nread;
469 	char	newname[200];
470 	char	cmd[100];
471 
472 	if (argc == 3)
473 	{
474 		filename = argv[2];
475 		argv[2] = NULL;
476 	}
477 	else
478 	{
479 		strcpy(newname, argv[1]);
480 		p = strrchr(newname, '.');
481 		if (p)
482 		{
483 			*p = '\0';
484 		}
485 		strcat(newname, ".pbm");
486 		filename = newname;
487 	}
488 
489 	argv_to_command(argv);
490 
491 	printf("Getting image for %s.  Image will be stored in %s\n", argv[1], filename);
492 
493 	switch (xpmtp_command(xpmtp_fd, command, response, sizeof(response)))
494 	{
495 		case -1:
496 			xpmtp_perror(argv[0]);
497 			command_quit(argc, argv);
498 			return;
499 		default:
500 			if (*response == '-')
501 			{
502 				printf("%s\n", response+1);
503 				return;
504 			}
505 	}
506 
507 	size = atoi(response + 1);
508 
509 	fp = fopen(filename, "w");
510 	if (fp == NULL)
511 	{
512 		perror(filename);
513 		return;
514 	}
515 
516 	while (size > 0)
517 	{
518 		n = MIN(sizeof(xpmtp_buf), size);
519 		nread = xpmtp_read(xpmtp_fd, xpmtp_buf, n);
520 		if (nread != n)
521 		{
522 			xpmtp_perror("get");
523 			break;
524 		}
525 		fwrite(xpmtp_buf, 1, n, fp);
526 		size -= n;
527 	}
528 
529 	fclose(fp);
530 	printf("OK Retrieved image:\n");
531 	sprintf(cmd, "ls -l %s", filename);
532 	system(cmd);
533 }
534 
535 #ifdef __STDC__
command_send(int argc,char ** argv)536 void	command_send(int argc, char **argv)
537 #else
538 void	command_send(argc, argv)
539 int	argc;
540 char	**argv;
541 #endif
542 {
543 	char	*p;
544 
545 	argv_to_command(argv);
546 
547 	switch (xpmtp_command(xpmtp_fd, command, response, sizeof(response)))
548 	{
549 		case -1:
550 			xpmtp_perror(argv[0]);
551 			command_quit(argc, argv);
552 			return;
553 		default:
554 			switch (*response)
555 			{
556 				case '-':
557 				case '+':
558 					printf("%s\n", response+1);
559 					break;
560 				case '*':
561 					printf("%s\n", response+1);
562 					while (xpmtp_getline(xpmtp_fd, response, sizeof(response)) >= 0)
563 					{
564 						if (*response == '.')
565 							break;
566 						printf("%s\n", response);
567 					}
568 					break;
569 				default:
570 					printf("%s\n", response);
571 					/*
572 					 * There are some errors...  List until we find either an +OK or -ERR
573 					 */
574 					while (xpmtp_getline(xpmtp_fd, response, sizeof(response)) >= 0)
575 					{
576 						if (*response == '-' || *response == '+' || *response)
577 						{
578 							printf("%s\n", response+1);
579 							return;
580 						}
581 						printf("%s\n", response);
582 					}
583 					break;
584 			}
585 			return;
586 	}
587 
588 }
589 
590 #ifdef __STDC__
command_unknown(int argc,char ** argv)591 void	command_unknown(int argc, char **argv)
592 #else
593 void	command_unknown(argc, argv)
594 int	argc;
595 char	**argv;
596 #endif
597 {
598 	printf("Unknown command '%s'.\n", argv[0]);
599 }
600 
601 #ifdef __STDC__
command_wildmap(int argc,char ** argv)602 void	command_wildmap(int argc, char **argv)
603 #else
604 void	command_wildmap(argc, argv)
605 int	argc;
606 char	**argv;
607 #endif
608 {
609 	FILE	*fp;
610 	char	*filename = "wildmap.map";
611 	char	*p;
612 	int	size, n, nread;
613 	char	cmd[100];
614 
615 	if (argc != 1)
616 	{
617 		filename = argv[argc - 1];
618 		argc--;
619 	}
620 
621 	argv_to_command(argv);
622 
623 	switch (xpmtp_command(xpmtp_fd, command, response, sizeof(response)))
624 	{
625 		case -1:
626 			xpmtp_perror(argv[0]);
627 			command_quit(argc, argv);
628 			return;
629 		case '*':
630 			printf("%s\n", response+1);
631 			while (xpmtp_getline(xpmtp_fd, response, sizeof(response)) >= 0)
632 			{
633 				if (*response == '.')
634 					break;
635 				printf("%s\n", response);
636 			}
637 			return;
638 		case '-':
639 			printf("%s\n", response+1);
640 			return;
641 	}
642 
643 	size = atoi(response + 1);
644 
645 	fp = fopen(filename, "w");
646 	if (fp == NULL)
647 	{
648 		perror(filename);
649 		return;
650 	}
651 
652 	while (size > 0)
653 	{
654 		n = MIN(sizeof(xpmtp_buf), size);
655 		nread = xpmtp_read(xpmtp_fd, xpmtp_buf, n);
656 		if (nread != n)
657 		{
658 			xpmtp_perror("get");
659 			break;
660 		}
661 		fwrite(xpmtp_buf, 1, n, fp);
662 		size -= n;
663 	}
664 
665 	fclose(fp);
666 	printf("OK Retrieved map:\n");
667 	sprintf(cmd, "ls -l %s", filename);
668 	system(cmd);
669 }
670 
usage()671 void	usage()
672 {
673 	printf("usage: xpmtp [options]\n");
674 	printf("\t-h host   Specify the XPMTP host, default = %s.\n",
675 		xpmtp_default_host());
676 	printf("\t-p port   Use port instead of the default XPMTP port, default = %d.\n", XPMTP_PORT);
677 	printf("\n");
678 }
679 
680 #ifdef __STDC__
done(int exit_value)681 void	done(int exit_value)
682 #else
683 void	done(exit_value)
684 int	exit_value;
685 #endif
686 {
687 	exit(exit_value);
688 }
689