/[sudobot]/trunk/lib/common/core/command.c
ViewVC logotype

Contents of /trunk/lib/common/core/command.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 575 - (show annotations)
Mon Jul 29 17:59:26 2024 UTC (8 months ago) by rakinar2
File MIME type: text/x-c
File size: 5156 byte(s)
chore: add trunk
1 #include <concord/chash.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <assert.h>
5 #include "command.h"
6 #include "../utils/strutils.h"
7 #include "../utils/xmalloc.h"
8 #include "../io/log.h"
9 #include "../commands/commands.h"
10
11 static void command_argv_create(const char *content, size_t *_argc, char ***_argv)
12 {
13 char **argv = NULL;
14 size_t argc = 0;
15 char *trimmed_content = str_trim(content);
16 size_t content_length = strlen(trimmed_content);
17 char *tmpstr = NULL;
18 size_t tmpstrlen = 0;
19
20 for (size_t i = 0; i < content_length; i++)
21 {
22 if (isspace(trimmed_content[i]))
23 {
24 tmpstr = xrealloc(tmpstr, ++tmpstrlen);
25 tmpstr[tmpstrlen - 1] = 0;
26 argv = xrealloc(argv, (++argc) * (sizeof(char *)));
27 argv[argc - 1] = tmpstr;
28 tmpstr = NULL;
29 tmpstrlen = 0;
30 continue;
31 }
32
33 tmpstr = xrealloc(tmpstr, ++tmpstrlen);
34 tmpstr[tmpstrlen - 1] = trimmed_content[i];
35 }
36
37 if (tmpstrlen > 0)
38 {
39 tmpstr = xrealloc(tmpstr, ++tmpstrlen);
40 tmpstr[tmpstrlen - 1] = 0;
41 argv = xrealloc(argv, (++argc) * (sizeof(char *)));
42 argv[argc - 1] = tmpstr;
43 }
44
45 *_argc = argc;
46 *_argv = argv;
47 free(trimmed_content);
48 }
49
50 static void command_argv_free(size_t argc, char **argv)
51 {
52 for (size_t i = 0; i < argc; i++)
53 {
54 free(argv[i]);
55 }
56
57 free(argv);
58 }
59
60 static void command_argv_print(size_t argc, char **argv)
61 {
62 #ifndef NDEBUG
63 log_debug("%s(%zu, %p):", __func__, argc, argv);
64
65 for (size_t i = 0; i < argc; i++)
66 {
67 log_debug(" argv[%zu]: %s", i, argv[i]);
68 }
69 #endif
70 }
71
72 #define PREFIX "-"
73
74 const struct command_info *command_find_by_name(const char *name)
75 {
76 for (size_t i = 0; i < command_count; i++)
77 {
78 if (strcmp(name, command_list[i].name) == 0)
79 {
80 return &command_list[i];
81 }
82 }
83
84 return NULL;
85 }
86
87 void command_on_interaction_handler(struct discord *client, const struct discord_interaction *interaction)
88 {
89 if (interaction->type != DISCORD_INTERACTION_APPLICATION_COMMAND)
90 return;
91
92 const char *command_name = interaction->data->name;
93
94 const struct command_info *command = command_find_by_name(command_name);
95
96 if (command == NULL)
97 {
98 log_debug("Command not found: %s", command_name);
99 return;
100 }
101
102 if ((command->mode & CMD_MODE_CHAT_INPUT_COMMAND_INTERACTION) != CMD_MODE_CHAT_INPUT_COMMAND_INTERACTION) {
103 log_debug("Command does not support chat input command interaction mode: %s", command_name);
104 return;
105 }
106
107 cmd_callback_t callback = command->callback;
108
109 cmdctx_t context = {
110 .type = CMDCTX_CHAT_INPUT_COMMAND_INTERACTION,
111 .is_legacy = false,
112 .is_chat_input_command_interaction = true,
113 .is_interaction = true,
114 .command_name = command_name,
115 .interaction = interaction
116 };
117
118 callback(client, context);
119 }
120
121 void command_on_message_handler(struct discord *client, const struct discord_message *message)
122 {
123 if (message->author->bot || !str_starts_with(message->content, PREFIX))
124 {
125 return;
126 }
127
128 size_t prefix_len = strlen(PREFIX);
129 assert(prefix_len != 0 && "Prefix cannot be an empty string");
130 const char *content = message->content + prefix_len;
131 char **argv;
132 size_t argc;
133
134 command_argv_create(content, &argc, &argv);
135 command_argv_print(argc, argv);
136
137 const char *command_name = argv[0];
138 const struct command_info *command = command_find_by_name(command_name);
139
140 if (command == NULL)
141 {
142 log_debug("Command not found: %s", command_name);
143 goto command_on_message_handler_end;
144 }
145
146 if ((command->mode & CMD_MODE_LEGACY) != CMD_MODE_LEGACY) {
147 log_debug("Command does not support legacy mode: %s", command_name);
148 goto command_on_message_handler_end;
149 }
150
151 cmd_callback_t callback = command->callback;
152
153 cmdctx_t context = {
154 .type = CMDCTX_LEGACY,
155 .is_legacy = true,
156 .is_chat_input_command_interaction = false,
157 .is_interaction = false,
158 .argc = argc,
159 .argv = (const char **)argv,
160 .command_name = command_name,
161 .message = message,
162 };
163
164 callback(client, context);
165
166 command_on_message_handler_end:
167 command_argv_free(argc, argv);
168 }
169
170 void register_slash_commands(struct discord *client, u64snowflake guild)
171 {
172 const struct discord_user *self = discord_get_self(client);
173 struct discord_bulk_overwrite_guild_application_commands *params = xcalloc(1, sizeof (*params));
174 size_t count = 1;
175
176 for (size_t i = 0; i < command_count; i++)
177 {
178 const struct command_info command = command_list[i];
179
180 params = xrealloc(params, sizeof (*params) * (++count));
181
182 params[i].name = (char *) command.name;
183 params[i].type = command.type;
184 params[i].description = (char *) command.description;
185 }
186
187 memset(&params[count - 1], 0, sizeof (*params));
188
189 assert(guild != 0);
190
191 discord_bulk_overwrite_guild_application_commands(client, self->id, guild, params, NULL);
192 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26