mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-05-06 03:57:14 +02:00
223 lines
6 KiB
C
223 lines
6 KiB
C
/*
|
|
Copyright (c) 2023 Roger Light <roger@atchoo.org>
|
|
|
|
All rights reserved. This program and the accompanying materials
|
|
are made available under the terms of the Eclipse Public License 2.0
|
|
and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
|
|
The Eclipse Public License is available at
|
|
https://www.eclipse.org/legal/epl-2.0/
|
|
and the Eclipse Distribution License is available at
|
|
http://www.eclipse.org/org/documents/edl-v10.php.
|
|
|
|
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
|
|
|
Contributors:
|
|
Roger Light - initial implementation and documentation.
|
|
*/
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "ctrl_shell_internal.h"
|
|
|
|
#ifdef WITH_EDITLINE
|
|
|
|
#define UNUSED(A) (void)(A)
|
|
|
|
static struct completion_tree_root *commands_pre_connect = NULL;
|
|
|
|
|
|
static void command_tree_create(void)
|
|
{
|
|
struct completion_tree_cmd *cmd;
|
|
struct completion_tree_arg_list *help_arg_list;
|
|
|
|
if(commands_pre_connect){
|
|
return;
|
|
}
|
|
|
|
commands_pre_connect = calloc(1, sizeof(struct completion_tree_root));
|
|
|
|
cmd = completion_tree_cmd_add(commands_pre_connect, NULL, "help");
|
|
help_arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
|
|
completion_tree_cmd_add(commands_pre_connect, help_arg_list, "auth");
|
|
completion_tree_cmd_add(commands_pre_connect, help_arg_list, "connect");
|
|
completion_tree_cmd_add(commands_pre_connect, help_arg_list, "exit");
|
|
}
|
|
|
|
|
|
void print_help(char **saveptr)
|
|
{
|
|
char *command = strtok_r(NULL, " ", saveptr);
|
|
if(command){
|
|
if(!strcasecmp(command, "auth")){
|
|
ctrl_shell_print_help_command("auth [username]");
|
|
ctrl_shell_printf("\nSet a username and password prior to connecting to a broker.\n");
|
|
}else if(!strcasecmp(command, "connect")){
|
|
ctrl_shell_print_help_command("connect");
|
|
ctrl_shell_print_help_command("connect mqtt://hostname[:port]");
|
|
ctrl_shell_print_help_command("connect mqtts://hostname[:port]");
|
|
ctrl_shell_print_help_command("connect ws://hostname[:port]");
|
|
ctrl_shell_print_help_command("connect wss://hostname[:port]");
|
|
ctrl_shell_printf("\nConnect to a broker using the provided transport and port.\n");
|
|
ctrl_shell_printf("If no URL is provided, connects to mqtt://localhost:1883\n");
|
|
}else if(!strcasecmp(command, "exit")){
|
|
ctrl_shell_print_help_command("exit");
|
|
ctrl_shell_printf("\nQuit the program\n");
|
|
}else if(!strcasecmp(command, "help")){
|
|
ctrl_shell_print_help_command("help <command>");
|
|
ctrl_shell_printf("\nFind help on a command using '%shelp <command>%s'\n", ANSI_INPUT, ANSI_RESET);
|
|
ctrl_shell_printf("Press tab multiple times to find currently available commands.\n");
|
|
}else{
|
|
ctrl_shell_printf("Unknown command '%s'\n", command);
|
|
}
|
|
}else{
|
|
ctrl_shell_printf("This is the mosquitto_ctrl interactive shell, for controlling aspects of a mosquitto broker.\n");
|
|
|
|
ctrl_shell_printf("Find help on a command using '%shelp <command>%s'\n", ANSI_INPUT, ANSI_RESET);
|
|
ctrl_shell_printf("Press tab multiple times to find currently available commands.\n\n");
|
|
|
|
ctrl_shell_printf("Example workflow:\n\n");
|
|
ctrl_shell_printf("> auth\n");
|
|
ctrl_shell_printf("username: admin\n");
|
|
ctrl_shell_printf("password:\n");
|
|
ctrl_shell_printf("> connect mqtt://localhost\n");
|
|
ctrl_shell_printf("mqtt://localhost:1883> dynsec\n");
|
|
ctrl_shell_printf("mqtt://localhost:1883|dynsec> createGroup newgroup\n");
|
|
ctrl_shell_printf("OK\n\n");
|
|
}
|
|
}
|
|
|
|
|
|
static void line_callback(char *line)
|
|
{
|
|
char *saveptr = NULL;
|
|
char *command;
|
|
|
|
if(!line){
|
|
ctrl_shell_callback_final(NULL);
|
|
return;
|
|
}
|
|
|
|
ctrl_shell_rtrim(line);
|
|
if(strlen(line) > 0){
|
|
add_history(line);
|
|
}else{
|
|
free(line);
|
|
return;
|
|
}
|
|
|
|
command = strtok_r(line, " ", &saveptr);
|
|
if(!command){
|
|
free(line);
|
|
return;
|
|
}
|
|
|
|
if(!strcasecmp(command, "auth")){
|
|
free(data.username);
|
|
char *username_i = strtok_r(NULL, " ", &saveptr);
|
|
if(username_i){
|
|
data.username = strdup(username_i);
|
|
}else{
|
|
char promptbuf[50];
|
|
snprintf(promptbuf, sizeof(promptbuf), "%susername:%s ", ANSI_INPUT, ANSI_RESET);
|
|
data.username = readline(promptbuf);
|
|
}
|
|
|
|
char pwbuf[200];
|
|
if(!ctrl_shell_get_password(pwbuf, sizeof(pwbuf))){
|
|
ctrl_shell_printf("No password.\n");
|
|
free(line);
|
|
return;
|
|
}
|
|
free(data.password);
|
|
data.password = strdup(pwbuf);
|
|
}else if(!strcasecmp(command, "connect")){
|
|
char *url = strtok_r(NULL, " ", &saveptr);
|
|
if(url){
|
|
if(!strncasecmp(url, "mqtt://", 7)){
|
|
url += 7;
|
|
data.port = 1883;
|
|
data.url_scheme = "mqtt";
|
|
}else if(!strncasecmp(url, "mqtts://", 8)){
|
|
#ifdef WITH_TLS
|
|
url += 8;
|
|
data.port = 8883;
|
|
data.url_scheme = "mqtts";
|
|
#else
|
|
ctrl_shell_printf("TLS support not available.\n");
|
|
free(line);
|
|
return;
|
|
#endif
|
|
}else if(!strncasecmp(url, "ws://", 5)){
|
|
url += 5;
|
|
data.port = 1883;
|
|
data.transport = MOSQ_T_WEBSOCKETS;
|
|
data.url_scheme = "ws";
|
|
}else if(!strncasecmp(url, "wss://", 6)){
|
|
#ifdef WITH_TLS
|
|
url += 6;
|
|
data.port = 8883;
|
|
data.transport = MOSQ_T_WEBSOCKETS;
|
|
data.url_scheme = "wss";
|
|
#else
|
|
ctrl_shell_printf("TLS support not available.\n");
|
|
free(line);
|
|
return;
|
|
#endif
|
|
}
|
|
char *hostname_i = strtok_r(url, ":", &saveptr);
|
|
char *port_i = strtok_r(NULL, ":", &saveptr);
|
|
|
|
if(!hostname_i){
|
|
ctrl_shell_printf("connect mqtt[s]://<hostname>:port\n");
|
|
free(line);
|
|
return;
|
|
}
|
|
free(data.hostname);
|
|
data.hostname = strdup(hostname_i);
|
|
if(port_i){
|
|
data.port = atoi(port_i);
|
|
}
|
|
}else{
|
|
if(data.hostname == NULL){
|
|
data.hostname = strdup("localhost");
|
|
}
|
|
if(data.port == PORT_UNDEFINED){
|
|
data.port = 1883;
|
|
}
|
|
}
|
|
|
|
ctrl_shell__connect();
|
|
}else if(!strcasecmp(command, "help")){
|
|
print_help(&saveptr);
|
|
}else if(!strcasecmp(command, "exit")){
|
|
data.run = 0;
|
|
}else{
|
|
ctrl_shell_printf("Unknown command '%s'\n", command);
|
|
}
|
|
|
|
free(line);
|
|
}
|
|
|
|
|
|
void ctrl_shell__pre_connect_cleanup(void)
|
|
{
|
|
completion_tree_free(commands_pre_connect);
|
|
commands_pre_connect = NULL;
|
|
}
|
|
|
|
|
|
void ctrl_shell__pre_connect_init(void)
|
|
{
|
|
command_tree_create();
|
|
ctrl_shell_completion_commands_set(commands_pre_connect);
|
|
ctrl_shell_line_callback_set(line_callback);
|
|
snprintf(prompt, sizeof(prompt), "%s>%s ", ANSI_INPUT, ANSI_RESET);
|
|
}
|
|
#endif
|