180709Sjake/*
280709Sjake * sdpcontrol.c
380709Sjake *
480709Sjake * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
580709Sjake * All rights reserved.
680709Sjake *
780709Sjake * Redistribution and use in source and binary forms, with or without
880709Sjake * modification, are permitted provided that the following conditions
980709Sjake * are met:
1080709Sjake * 1. Redistributions of source code must retain the above copyright
1180709Sjake *    notice, this list of conditions and the following disclaimer.
1280709Sjake * 2. Redistributions in binary form must reproduce the above copyright
1380709Sjake *    notice, this list of conditions and the following disclaimer in the
1480709Sjake *    documentation and/or other materials provided with the distribution.
1580709Sjake *
1680709Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1780709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1880709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1980709Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2080709Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2180709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2280709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2380709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2480709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2580709Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2680709Sjake * SUCH DAMAGE.
2780709Sjake *
2880709Sjake * $Id: sdpcontrol.c,v 1.1 2003/09/08 02:27:27 max Exp $
2980709Sjake * $FreeBSD$
3080709Sjake */
3180709Sjake
3280709Sjake#include <assert.h>
3380709Sjake#include <bluetooth.h>
3480709Sjake#include <err.h>
3597446Sjake#include <errno.h>
3680709Sjake#include <sdp.h>
3780709Sjake#include <stdio.h>
3880709Sjake#include <stdlib.h>
39205258Smarius#include <string.h>
40205258Smarius#include <unistd.h>
41182767Smarius#include "sdpcontrol.h"
42182767Smarius
43205258Smarius/* Prototypes */
44205258Smariusstatic int                  do_sdp_command	(bdaddr_p, char const *, int,
45205258Smarius						 int, char **);
4680709Sjakestatic struct sdp_command * find_sdp_command	(char const *,
4780709Sjake						 struct sdp_command *);
4880709Sjakestatic void                 print_sdp_command	(struct sdp_command *);
4997027Sjakestatic void                 usage		(void);
5097027Sjake
51205258Smarius/* Main */
52205258Smariusint
53205258Smariusmain(int argc, char *argv[])
54205258Smarius{
55205258Smarius	char const	*control = SDP_LOCAL_PATH;
56205258Smarius	int		 n, local;
57205258Smarius	bdaddr_t	 bdaddr;
58205258Smarius
59205258Smarius	memset(&bdaddr, 0, sizeof(bdaddr));
60205258Smarius	local = 0;
61182767Smarius
6297027Sjake	/* Process command line arguments */
6380709Sjake	while ((n = getopt(argc, argv, "a:c:lh")) != -1) {
6497027Sjake		switch (n) {
6597027Sjake		case 'a': /* bdaddr */
66205258Smarius			if (!bt_aton(optarg, &bdaddr)) {
67205258Smarius				struct hostent  *he = NULL;
68182767Smarius
69182767Smarius				if ((he = bt_gethostbyname(optarg)) == NULL)
70205258Smarius					errx(1, "%s: %s", optarg, hstrerror(h_errno));
71205258Smarius
72205258Smarius				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
73181398Smarius			}
74205258Smarius			break;
75181398Smarius
7697027Sjake		case 'c': /* control socket */
7797027Sjake			control = optarg;
7880709Sjake			break;
79102040Sjake
80102040Sjake		case 'l': /* local sdpd */
81102040Sjake			local = 1;
82102040Sjake			break;
83205258Smarius
84205258Smarius		case 'h':
85205258Smarius		default:
8697027Sjake			usage();
87102040Sjake			/* NOT REACHED */
88102040Sjake		}
8980709Sjake	}
9088652Sjake
91102040Sjake	argc -= optind;
92102040Sjake	argv += optind;
93102040Sjake
94102040Sjake	if (*argv == NULL)
95205258Smarius		usage();
96205258Smarius
97205258Smarius	return (do_sdp_command(&bdaddr, control, local, argc, argv));
98205258Smarius}
99205258Smarius
100205258Smarius/* Execute commands */
101205258Smariusstatic int
102205258Smariusdo_sdp_command(bdaddr_p bdaddr, char const *control, int local,
103205258Smarius		int argc, char **argv)
10488652Sjake{
10588652Sjake	char			*cmd = argv[0];
10697027Sjake	struct sdp_command	*c = NULL;
107112697Sjake	void			*xs = NULL;
108112697Sjake	int			 e, help;
109102040Sjake
110102040Sjake	help = 0;
111102040Sjake	if (strcasecmp(cmd, "help") == 0) {
112102040Sjake		argc --;
113102040Sjake		argv ++;
11488652Sjake
11588652Sjake		if (argc <= 0) {
11688652Sjake			fprintf(stdout, "Supported commands:\n");
11788652Sjake			print_sdp_command(sdp_commands);
11888652Sjake			fprintf(stdout, "\nFor more information use " \
11988652Sjake				"'help command'\n");
12088652Sjake
12180709Sjake			return (OK);
122102040Sjake		}
123102040Sjake
12491224Sjake		help = 1;
125102040Sjake		cmd = argv[0];
126205258Smarius	}
127102040Sjake
128102040Sjake	c = find_sdp_command(cmd, sdp_commands);
129205258Smarius	if (c == NULL) {
13097027Sjake		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
131205258Smarius		return (ERROR);
132102040Sjake	}
133205258Smarius
13497027Sjake	if (!help) {
135205258Smarius		if (!local) {
13697027Sjake			if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
13784182Sjake				usage();
138205258Smarius
13997027Sjake			xs = sdp_open(NG_HCI_BDADDR_ANY, bdaddr);
140205258Smarius		} else
141102040Sjake			xs = sdp_open_local(control);
142205258Smarius
143102040Sjake		if (xs == NULL)
144205258Smarius			errx(1, "Could not create SDP session object");
145205258Smarius		if (sdp_error(xs) == 0)
146205258Smarius			e = (c->handler)(xs, -- argc, ++ argv);
147205258Smarius		else
148108386Sjake			e = ERROR;
14997027Sjake	} else
150102040Sjake		e = USAGE;
151102040Sjake
15283053Sobrien	switch (e) {
15391224Sjake	case OK:
15480709Sjake	case FAILED:
155108166Sjake		break;
15680709Sjake
15780709Sjake	case ERROR:
15891224Sjake		fprintf(stdout, "Could not execute command \"%s\". %s\n",
15997027Sjake			cmd, strerror(sdp_error(xs)));
16080709Sjake		break;
161205258Smarius
162102040Sjake	case USAGE:
163102040Sjake		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
16480709Sjake		break;
16580709Sjake
16680709Sjake	default: assert(0); break;
167	}
168
169	sdp_close(xs);
170
171	return (e);
172} /* do_sdp_command */
173
174/* Try to find command in specified category */
175static struct sdp_command *
176find_sdp_command(char const *command, struct sdp_command *category)
177{
178	struct sdp_command	*c = NULL;
179
180	for (c = category; c->command != NULL; c++) {
181		char	*c_end = strchr(c->command, ' ');
182
183		if (c_end != NULL) {
184			int	len = c_end - c->command;
185
186			if (strncasecmp(command, c->command, len) == 0)
187				return (c);
188		} else if (strcasecmp(command, c->command) == 0)
189				return (c);
190	}
191
192	return (NULL);
193} /* find_sdp_command */
194
195/* Print commands in specified category */
196static void
197print_sdp_command(struct sdp_command *category)
198{
199	struct sdp_command	*c = NULL;
200
201	for (c = category; c->command != NULL; c++)
202		fprintf(stdout, "\t%s\n", c->command);
203} /* print_sdp_command */
204
205/* Usage */
206static void
207usage(void)
208{
209	fprintf(stderr,
210"Usage: sdpcontrol options command\n" \
211"Where options are:\n"
212"	-a address	address to connect to\n" \
213"	-c path		path to the control socket (default is %s)\n" \
214"	-h		display usage and quit\n" \
215"	-l		connect to the local SDP server via control socket\n" \
216"	command		one of the supported commands\n", SDP_LOCAL_PATH);
217	exit(255);
218} /* usage */
219
220