diff options
Diffstat (limited to 'commands.c')
-rw-r--r-- | commands.c | 288 |
1 files changed, 244 insertions, 44 deletions
@@ -90,7 +90,7 @@ static struct pref_type_suff { } sus_strings[] = { {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :Andrew is very sus.\n")}, {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :I was the impostor, but you only know because I killed you.\n")}, - {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :\x1b(0\n")}, + {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :\\x1b(0\n")}, {STRING(":1HC000000 KILL "), 1, STRING(" :Ejected (1 Impostor remains)\n")}, {STRING(":1HC000000 KILL "), 1, STRING(" :Ejected, and the crewmates have won.\n")}, }, cr_strings[] = { @@ -146,7 +146,7 @@ int spam_command(struct string sender, struct string original_message, struct st } char err; - uint64_t count = str_to_unsigned(argv[2], &err); + uint64_t count = str_to_unsigned(argv[1], &err); if (err || (count > MAX_SPAM_COUNT && !is_local)) { privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Unknown number or number exceeds limit.")}); return 0; @@ -161,19 +161,62 @@ int spam_command(struct string sender, struct string original_message, struct st wasspace = (original_message.data[offset] == ' '); - if (found >= 3 && !wasspace) + if (found >= 2 && !wasspace) break; } - if (found < 3) { - WRITES(2, STRING("WARNING: Apparently there was no third argument... shouldn't happen.\n")); + if (found < 2) { + WRITES(2, STRING("WARNING: Apparently there was no second argument... shouldn't happen.\n")); return 0; } - struct string message[] = {{.data = original_message.data + offset, .len = original_message.len - offset}}; + struct command_def *cmd = get_table_index(user_commands, argv[2]); + if (cmd) { + if (!cmd->local_only) { + if (cmd->privs.len != 0 && sender.len != 3 && !is_local) { + struct user_info *user = get_table_index(user_list, sender); + if (!user) + return 1; // really shouldn't happen + if (!STRING_EQ(user->opertype, cmd->privs)) { + SEND(STRING(":1HC000000 NOTICE ")); + SEND(to); + SEND(STRING(" :You are not authorized to execute that command.\n")); + + return 0; + } + + if (cmd->func == spam_command) { + SEND(STRING(":1HC000000 NOTICE ")); + SEND(to); + SEND(STRING(" :Spam recursion is not allowed. The limit is for your own sake, please do not violate it.\n")); + + return 0; + } + } + } else { + SEND(STRING(":1HC000000 NOTICE ")); + SEND(to); + SEND(STRING(" :Spamming of local-only commands is disabled.\n")); + + return 0; + } + } else { + SEND(STRING(":1HC000000 NOTICE ")); + SEND(to); + SEND(STRING(" :Unknown command.\n")); + + return 0; + } + + struct string fake_original_message = {.data = original_message.data + offset, .len = original_message.len - offset}; + WRITES(2, fake_original_message); + WRITES(2, STRING("\n")); - for (uint64_t i = 0; i < count; i++) - privmsg(STRING("1HC000000"), argv[1], 1, message); + for (uint64_t i = 0; i < count; i++) { + int ret = cmd->func(sender, fake_original_message, to, argc - 2, &(argv[2]), 0); + if (ret) + return ret; + } return 0; } @@ -181,7 +224,7 @@ static struct command_def spam_command_def = { .func = spam_command, .privs = STRING("NetAdmin"), .local_only = 0, - .summary = STRING("Repeats a message to a target <n> times"), + .summary = STRING("Repeats a command <n> times"), }; int clear_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) { @@ -220,7 +263,7 @@ int clear_command(struct string sender, struct string original_message, struct s if (user) SENDCLIENT(user->nick); else - SENDCLIENT(user_list.array[i].name); + SENDCLIENT(channel->user_list.array[i].name); SENDCLIENT(STRING(" :\r\n")); } @@ -236,11 +279,65 @@ static struct command_def clear_command_def = { .summary = STRING("Clears a channel"), }; +struct sh_command_args { + char *command; + struct string to; +}; +void * async_sh_command(void *tmp) { + struct sh_command_args *sh_args = tmp; + + FILE *f = popen(sh_args->command, "r"); + free(sh_args->command); + + char *line = NULL; + size_t buflen; + while (1) { + ssize_t len = getline(&line, &buflen, f); + if (len <= 0) + break; + + struct string linestr = {.data = line, .len = (size_t)(len)}; + while (linestr.len > 0 && (linestr.data[linestr.len-1] == '\n' || linestr.data[linestr.len-1] == '\r')) + linestr.len--; + if (linestr.len == 0) + linestr = STRING(" "); + pthread_mutex_lock(&send_lock); + SEND(STRING(":1HC000000 PRIVMSG ")); + SEND(sh_args->to); + SEND(STRING(" :")); + SEND(linestr); + SEND(STRING("\n")); + + SENDCLIENT(STRING(":")); + SENDCLIENT(nick); + SENDCLIENT(STRING("!e@e PRIVMSG ")); + SENDCLIENT(sh_args->to); + SENDCLIENT(STRING(" :")); + SENDCLIENT(linestr); + SENDCLIENT(STRING("\r\n")); + pthread_mutex_unlock(&send_lock); + } + + free(line); + + pclose(f); + + free(sh_args->to.data); + free(sh_args); + + return 0; +} + int sh_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) { if (!is_local) { return 0; } + if (argc < 2) { + privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")}); + return 0; + } + char wasspace = 1; uint64_t offset = 0; char found = 0; @@ -255,56 +352,156 @@ int sh_command(struct string sender, struct string original_message, struct stri } if (found < 1) { - WRITES(2, STRING("WARNING: Apparently there was no third argument... shouldn't happen.\n")); + WRITES(2, STRING("WARNING: Apparently there was no argument... shouldn't happen.\n")); return 0; } struct string command = {.data = original_message.data + offset, .len = original_message.len - offset}; - char command_nullstr[command.len+1]; - memcpy(command_nullstr, command.data, command.len); - command_nullstr[command.len] = '\0'; + struct sh_command_args *sh_args; + sh_args = malloc(sizeof(*sh_args)); + if (!sh_args) { + WRITES(2, STRING("ERROR: OOM\n")); + return 0; + } - FILE *f = popen(command_nullstr, "r"); + sh_args->command = malloc(command.len+1); + if (!sh_args->command) { + free(sh_args); + WRITES(2, STRING("ERROR: OOM\n")); + return 0; + } + memcpy(sh_args->command, command.data, command.len); + sh_args->command[command.len] = '\0'; + + sh_args->to.len = to.len; + sh_args->to.data = malloc(to.len); + if (!sh_args->to.data) { + free(sh_args->command); + free(sh_args); + WRITES(2, STRING("ERROR: OOM\n")); + return 0; + } + memcpy(sh_args->to.data, to.data, to.len); - char *line = NULL; - size_t buflen; - while (1) { - ssize_t len = getline(&line, &buflen, f); - if (len <= 0) + pthread_t trash; + pthread_create(&trash, NULL, async_sh_command, sh_args); + + return 0; +} +static struct command_def sh_command_def = { + .func = sh_command, + .privs = STRING("NetAdmin"), + .local_only = 1, + .summary = STRING("Executes a command locally"), +}; + +int kill_old_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) { + if (argc < 2) { + privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")}); + return 0; + } + + uint64_t current_time = (uint64_t)time(0); + char err; + uint64_t age = str_to_unsigned(argv[1], &err); + if (err) { + privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Invalid age!")}); + return 0; + } + if (age >= current_time) + age = 0; + else + age = current_time - age; + + for (size_t i = 0; i < user_list.len; i++) { + struct user_info *user = user_list.array[i].ptr; + if ((user->user_ts <= age || STRING_EQ(user->nick, STRING("OperServ"))) && !STRING_EQ(user->server, STRING("1HC"))) { + SEND(STRING(":1HC000000 KILL ")); + SEND(user_list.array[i].name); + SEND(STRING(" :Your connection is too old.\n")); + } + } + + return 0; +} +static struct command_def kill_old_command_def = { + .func = kill_old_command, + .privs = STRING("NetAdmin"), + .local_only = 0, + .summary = STRING("Kills old connections (with a time you specify), and OperServ because OperServ is wrong"), +}; + +int echo_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) { + if (argc < 2) { + privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")}); + return 0; + } + + char wasspace = 1; + uint64_t offset = 0; + char found = 0; + for (; offset < original_message.len; offset++) { + if (original_message.data[offset] == ' ' && !wasspace) + found++; + + wasspace = (original_message.data[offset] == ' '); + + if (found >= 1 && !wasspace) break; + } - struct string linestr = {.data = line, .len = (size_t)(len) - 1}; - if (linestr.len > 0 && linestr.data[linestr.len-1] == '\n') - linestr.len--; - if (linestr.len > 0 && linestr.data[linestr.len-1] == '\r') - linestr.len--; - SEND(STRING(":1HC000000 PRIVMSG ")); - SEND(to); - SEND(STRING(" :")); - SEND(linestr); - SEND(STRING("\n")); + if (found < 1) { + WRITES(2, STRING("WARNING: Apparently there was no second argument... shouldn't happen.\n")); + return 0; + } - SENDCLIENT(STRING(":")); - SENDCLIENT(nick); - SENDCLIENT(STRING("!e@e PRIVMSG ")); - SENDCLIENT(to); - SENDCLIENT(STRING(" :")); - SENDCLIENT(linestr); - SENDCLIENT(STRING("\r\n")); + struct string message[] = {{.data = original_message.data + offset, .len = original_message.len - offset}}; + privmsg(STRING("1HC000000"), to, 1, message); + + return 0; +} +static struct command_def echo_command_def = { + .func = echo_command, + .privs = {0}, + .local_only = 0, + .summary = STRING("Repeats a message back"), +}; + +int tell_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) { + if (argc < 3) { + privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")}); + return 0; } - free(line); + char wasspace = 1; + uint64_t offset = 0; + char found = 0; + for (; offset < original_message.len; offset++) { + if (original_message.data[offset] == ' ' && !wasspace) + found++; - pclose(f); + wasspace = (original_message.data[offset] == ' '); + + if (found >= 2 && !wasspace) + break; + } + + if (found < 2) { + WRITES(2, STRING("WARNING: Apparently there was no second argument... shouldn't happen.\n")); + return 0; + } + + struct string message[] = {{.data = original_message.data + offset, .len = original_message.len - offset}}; + privmsg(STRING("1HC000000"), argv[1], 1, message); return 0; } -static struct command_def sh_command_def = { - .func = sh_command, +static struct command_def tell_command_def = { + .func = tell_command, .privs = STRING("NetAdmin"), - .local_only = 1, - .summary = STRING("Executes a command locally"), + .local_only = 0, + .summary = STRING("Sends a message to a target"), }; int init_user_commands(void) { @@ -316,9 +513,12 @@ int init_user_commands(void) { set_table_index(&user_commands, STRING("sus"), &sus_command_def); set_table_index(&user_commands, STRING("cr"), &cr_command_def); set_table_index(&user_commands, STRING("help"), &help_command_def); -// set_table_index(&user_commands, STRING("spam"), &spam_command_def); + set_table_index(&user_commands, STRING("spam"), &spam_command_def); set_table_index(&user_commands, STRING("clear"), &clear_command_def); set_table_index(&user_commands, STRING("sh"), &sh_command_def); + set_table_index(&user_commands, STRING("kill_old"), &kill_old_command_def); + set_table_index(&user_commands, STRING("echo"), &echo_command_def); + set_table_index(&user_commands, STRING("tell"), &tell_command_def); return 0; } |