* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
if (connection_write(connection, data, len) == len)
return ERROR_OK;
- t_con->closed = 1;
+ t_con->closed = true;
return ERROR_SERVER_REMOTE_CLOSED;
}
{
struct connection *connection = priv;
struct telnet_connection *t_con = connection->priv;
- int i;
+ size_t i;
+ size_t tmp;
- /* if there is no prompt, simply output the message */
- if (t_con->line_cursor < 0) {
+ /* If the prompt is not visible, simply output the message. */
+ if (!t_con->prompt_visible) {
telnet_outputline(connection, string);
return;
}
- /* clear the command line */
- for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
- telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
- for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
- telnet_write(connection, " ", i > 16 ? 16 : i);
- for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
- telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
+ /* Clear the command line. */
+ tmp = strlen(t_con->prompt) + t_con->line_size;
+
+ for (i = 0; i < tmp; i += 16)
+ telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
+ MIN(tmp - i, 16));
+
+ for (i = 0; i < tmp; i += 16)
+ telnet_write(connection, " ", MIN(tmp - i, 16));
+
+ for (i = 0; i < tmp; i += 16)
+ telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
+ MIN(tmp - i, 16));
- /* output the message */
telnet_outputline(connection, string);
- /* put the command line to its previous state */
+ /* Put the command line to its previous state. */
telnet_prompt(connection);
telnet_write(connection, t_con->line, t_con->line_size);
- for (i = t_con->line_size; i > t_con->line_cursor; i--)
+
+ for (i = t_con->line_cursor; i < t_con->line_size; i++)
telnet_write(connection, "\b", 1);
}
static int telnet_new_connection(struct connection *connection)
{
- struct telnet_connection *telnet_connection = malloc(sizeof(struct telnet_connection));
+ struct telnet_connection *telnet_connection;
struct telnet_service *telnet_service = connection->service->priv;
int i;
+ telnet_connection = malloc(sizeof(struct telnet_connection));
+
+ if (!telnet_connection) {
+ LOG_ERROR("Failed to allocate telnet connection.");
+ return ERROR_FAIL;
+ }
+
connection->priv = telnet_connection;
/* initialize telnet connection information */
- telnet_connection->closed = 0;
+ telnet_connection->closed = false;
telnet_connection->line_size = 0;
telnet_connection->line_cursor = 0;
- telnet_connection->option_size = 0;
telnet_connection->prompt = strdup("> ");
+ telnet_connection->prompt_visible = true;
telnet_connection->state = TELNET_STATE_DATA;
/* output goes through telnet connection */
{
struct telnet_connection *t_con = connection->priv;
- int last_history = (t_con->current_history > 0) ?
+ size_t last_history = (t_con->current_history > 0) ?
t_con->current_history - 1 :
TELNET_LINE_HISTORY_SIZE-1;
telnet_history_go(connection, last_history);
static void telnet_history_down(struct connection *connection)
{
struct telnet_connection *t_con = connection->priv;
+ size_t next_history;
- int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
+ next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
telnet_history_go(connection, next_history);
}
+static void telnet_move_cursor(struct connection *connection, size_t pos)
+{
+ struct telnet_connection *tc;
+ size_t tmp;
+
+ tc = connection->priv;
+
+ if (pos < tc->line_cursor) {
+ tmp = tc->line_cursor - pos;
+
+ for (size_t i = 0; i < tmp; i += 16)
+ telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
+ MIN(tmp - i, 16));
+ } else {
+ tmp = pos - tc->line_cursor;
+
+ for (size_t i = 0; i < tmp; i += 16)
+ telnet_write(connection, tc->line + tc->line_cursor + i,
+ MIN(tmp - i, 16));
+ }
+
+ tc->line_cursor = pos;
+}
+
static int telnet_input(struct connection *connection)
{
int bytes_read;
t_con->line[t_con->line_size++] = *buf_p;
t_con->line_cursor++;
} else {
- int i;
+ size_t i;
memmove(t_con->line + t_con->line_cursor + 1,
t_con->line + t_con->line_cursor,
t_con->line_size - t_con->line_cursor);
telnet_write(connection, "\r\n\x00", 3);
if (strcmp(t_con->line, "history") == 0) {
- int i;
+ size_t i;
for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) {
/* the t_con->next_history line contains empty string
* (unless NULL), thus it is not printed */
t_con->line_size = 0;
/* to suppress prompt in log callback during command execution */
- t_con->line_cursor = -1;
+ t_con->prompt_visible = false;
if (strcmp(t_con->line, "shutdown") == 0)
telnet_save_history(t_con);
retval = command_run_line(command_context, t_con->line);
t_con->line_cursor = 0;
+ t_con->prompt_visible = true;
if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
return ERROR_SERVER_REMOTE_CLOSED;
} else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */
if (t_con->line_cursor > 0) {
if (t_con->line_cursor != t_con->line_size) {
- int i;
+ size_t i;
telnet_write(connection, "\b", 1);
t_con->line_cursor--;
t_con->line_size--;
telnet_history_up(connection);
else if (*buf_p == CTRL('N')) /* cursor down */
telnet_history_down(connection);
+ else if (*buf_p == CTRL('A'))
+ telnet_move_cursor(connection, 0);
+ else if (*buf_p == CTRL('E'))
+ telnet_move_cursor(connection, t_con->line_size);
else
LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p);
}
/* Remove character */
if (*buf_p == '~') {
if (t_con->line_cursor < t_con->line_size) {
- int i;
+ size_t i;
t_con->line_size--;
/* remove char from line buffer */
memmove(t_con->line + t_con->line_cursor,
break;
default:
LOG_ERROR("unknown telnet state");
- exit(-1);
+ return ERROR_FAIL;
}
bytes_read--;
return ERROR_OK;
}
- struct telnet_service *telnet_service = malloc(sizeof(struct telnet_service));
+ struct telnet_service *telnet_service =
+ malloc(sizeof(struct telnet_service));
+
+ if (!telnet_service) {
+ LOG_ERROR("Failed to allocate telnet service.");
+ return ERROR_FAIL;
+ }
telnet_service->banner = banner;
- return add_service("telnet",
- telnet_port,
- 1,
- telnet_new_connection,
- telnet_input,
- telnet_connection_closed,
+ int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED,
+ telnet_new_connection, telnet_input, telnet_connection_closed,
telnet_service);
+
+ if (ret != ERROR_OK) {
+ free(telnet_service);
+ return ret;
+ }
+
+ return ERROR_OK;
}
/* daemon configuration command telnet_port */
telnet_port = strdup("4444");
return register_commands(cmd_ctx, NULL, telnet_command_handlers);
}
+
+void telnet_service_free(void)
+{
+ free(telnet_port);
+}