/* execute.c * * * Copyright (C) 2014 Toxic All Rights Reserved. * * This file is part of Toxic. * * Toxic is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Toxic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Toxic. If not, see . * */ #include #include #include #include "toxic.h" #include "windows.h" #include "execute.h" #include "chat_commands.h" #include "global_commands.h" #include "group_commands.h" #include "line_info.h" #include "misc_tools.h" #include "notify.h" struct cmd_func { const char *name; void (*func)(WINDOW *w, ToxWindow *, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); }; static struct cmd_func global_commands[] = { { "/accept", cmd_accept }, { "/add", cmd_add }, { "/avatar", cmd_avatar }, { "/clear", cmd_clear }, { "/connect", cmd_connect }, { "/decline", cmd_decline }, { "/exit", cmd_quit }, { "/group", cmd_groupchat }, { "/help", cmd_prompt_help }, { "/log", cmd_log }, { "/myid", cmd_myid }, { "/myqr", cmd_myqr }, { "/nick", cmd_nick }, { "/note", cmd_note }, { "/nospam", cmd_nospam }, { "/q", cmd_quit }, { "/quit", cmd_quit }, { "/requests", cmd_requests }, { "/status", cmd_status }, #ifdef AUDIO { "/lsdev", cmd_list_devices }, { "/sdev", cmd_change_device }, #endif /* AUDIO */ #ifdef VIDEO { "/lsvdev", cmd_list_video_devices }, { "/svdev" , cmd_change_video_device }, #endif /* VIDEO */ #ifdef PYTHON { "/run", cmd_run }, #endif /* PYTHON */ { NULL, NULL }, }; static struct cmd_func chat_commands[] = { { "/cancel", cmd_cancelfile }, { "/invite", cmd_groupinvite }, { "/join", cmd_join_group }, { "/savefile", cmd_savefile }, { "/sendfile", cmd_sendfile }, #ifdef AUDIO { "/call", cmd_call }, { "/answer", cmd_answer }, { "/reject", cmd_reject }, { "/hangup", cmd_hangup }, { "/mute", cmd_mute }, { "/sense", cmd_sense }, #endif /* AUDIO */ #ifdef VIDEO { "/video", cmd_video }, #endif /* VIDEO */ { NULL, NULL }, }; static struct cmd_func group_commands[] = { { "/title", cmd_set_title }, #ifdef AUDIO { "/mute", cmd_mute }, { "/sense", cmd_sense }, #endif /* AUDIO */ { NULL, NULL }, }; /* Parses input command and puts args into arg array. Returns number of arguments on success, -1 on failure. */ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) { char *cmd = strdup(input); if (cmd == NULL) exit_toxic_err("failed in parse_command", FATALERR_MEMORY); int num_args = 0; int i = 0; /* index of last char in an argument */ /* characters wrapped in double quotes count as one arg */ while (num_args < MAX_NUM_ARGS) { int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */ if (*cmd == '\"') { qt_ofst = 1; i = char_find(1, cmd, '\"'); if (cmd[i] == '\0') { const char *errmsg = "Invalid argument. Did you forget a closing \"?"; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); free(cmd); return -1; } } else { i = char_find(0, cmd, ' '); } memcpy(args[num_args], cmd, i + qt_ofst); args[num_args++][i + qt_ofst] = '\0'; if (cmd[i] == '\0') /* no more args */ break; char tmp[MAX_STR_SIZE]; snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]); strcpy(cmd, tmp); /* tmp will always fit inside cmd */ } free(cmd); return num_args; } /* Matches command to respective function. Returns 0 on match, 1 on no match */ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands, char (*args)[MAX_STR_SIZE]) { int i; for (i = 0; commands[i].name != NULL; ++i) { if (strcmp(args[0], commands[i].name) == 0) { (commands[i].func)(w, self, m, num_args - 1, args); return 0; } } return 1; } void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode) { if (string_is_empty(input)) return; char args[MAX_NUM_ARGS][MAX_STR_SIZE]; int num_args = parse_command(w, self, input, args); if (num_args == -1) return; /* Try to match input command to command functions. If non-global command mode is specified, try specified mode's commands first, then upon failure try global commands. Note: Global commands must come last in case of duplicate command names */ switch (mode) { case CHAT_COMMAND_MODE: if (do_command(w, self, m, num_args, chat_commands, args) == 0) return; break; case GROUPCHAT_COMMAND_MODE: if (do_command(w, self, m, num_args, group_commands, args) == 0) return; break; } if (do_command(w, self, m, num_args, global_commands, args) == 0) return; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command."); }