fd6663ecf6fb0a4e517ace1f6b38a0d42f3294dc
[citadel] / ctdlsh / main.c
1 /*
2  * (c) 2009-2017 by Art Cancro and citadel.org
3  * This program is released under the terms of the GNU General Public License v3.
4  */
5
6 #include "ctdlsh.h"
7
8
9 int cmd_quit(int sock, char *cmdbuf)
10 {
11         return (cmdret_exit);
12 }
13
14
15 /*
16  * Commands understood by ctdlsh
17  */
18 typedef struct {
19         char *name;
20         ctdlsh_cmdfunc_t *func;
21         char *doc;
22 } COMMAND;
23
24 COMMAND commands[] = {
25         {"?", cmd_help, "Display this message"},
26         {"help", cmd_help, "Display this message"},
27         {"date", cmd_datetime, "Print the server's date and time"},
28         {"config", cmd_config, "Configure the Citadel server"},
29         {"export", cmd_export, "Export all Citadel databases"},
30         {"shutdown", cmd_shutdown, "Shut down the Citadel server"},
31         {"time", cmd_datetime, "Print the server's date and time"},
32         {"passwd", cmd_passwd, "Set or change an account password"},
33         {"who", cmd_who, "Display a list of online users"},
34         {"exit", cmd_quit, "Quit using ctdlsh"},
35         {"quit", cmd_quit, "Quit using ctdlsh"},
36         {"mailq", cmd_mailq, "Show the outbound email queue"},
37         {NULL, NULL, NULL}
38 };
39
40
41
42 struct wow {
43         char *cmd[5];                   // increase this if we need to have larger commands
44         char *description;
45 };
46
47 struct wow wows[] = {
48         {{ "show", "eggs" }                             , "show how many eggs are available for serving"        },
49         {{ "kill", "mark", "zuckerberg" }               , "die motherfucker die"                                },
50         {{ "show", "undead", "zombies", "real" }        , "show how many zombies are actually undead"           },
51         {{ "show", "undead", "zombies", "hollywood" }   , "show how many zombies are hollywood communists"      }
52 };
53
54
55
56
57
58
59
60
61 int cmd_help(int sock, char *cmdbuf)
62 {
63         int i;
64
65         for (i = 0; commands[i].func != NULL; ++i) {
66                 printf("%-10s %s\n", commands[i].name, commands[i].doc);
67         }
68 }
69
70
71 /* Auto-completer function */
72 char *command_generator(const char *text, int state)
73 {
74         static int list_index;
75         static int len;
76         char *name;
77
78         if (!state) {
79                 list_index = 0;
80                 len = strlen(text);
81         }
82
83         while (name = commands[list_index].name) {
84                 ++list_index;
85
86                 if (!strncmp(name, text, len)) {
87                         return (strdup(name));
88                 }
89         }
90
91         return (NULL);
92 }
93
94
95 /* Auto-completer function */
96 char **ctdlsh_completion(const char *text, int start, int end)
97 {
98         char **matches = (char **) NULL;
99
100         rl_completer_word_break_characters = " ";
101         if (start == 0) {
102                 matches = rl_completion_matches(text, command_generator);
103         } else {
104                 rl_bind_key('\t', rl_abort);
105         }
106
107         return (matches);
108 }
109
110
111 int do_one_command(int server_socket, char *cmd)
112 {
113         int i;
114         int ret;
115         for (i = 0; commands[i].func != NULL; ++i) {
116                 if (!strncasecmp(cmd, commands[i].name, strlen(commands[i].name))) {
117                         ret = (*commands[i].func) (server_socket, cmd);
118                 }
119         }
120         return ret;
121 }
122
123
124 void do_main_loop(int server_socket)
125 {
126         char *cmd = NULL;
127         char prompt[1024];
128         char buf[1024];
129         char server_reply[1024];
130         int i;
131         int ret = (-1);
132
133
134         strcpy(prompt, "> ");
135
136         /* Do an INFO command and learn the hostname for the prompt */
137         sock_puts(server_socket, "INFO");
138         sock_getln(server_socket, buf, sizeof buf);
139         if (buf[0] == '1') {
140                 i = 0;
141                 while (sock_getln(server_socket, buf, sizeof buf), strcmp(buf, "000")) {
142                         if (i == 1) {
143                                 sprintf(prompt, "\n%s> ", buf);
144                         }
145                         ++i;
146                 }
147         }
148
149         /* Tell libreadline how we will help with auto-completion of commands */
150         rl_attempted_completion_function = ctdlsh_completion;
151
152         /* Here we go ... main command loop */
153         while ((ret != cmdret_exit) && (cmd = readline(prompt))) {
154
155                 if ((cmd) && (*cmd)) {
156                         add_history(cmd);
157                         ret = do_one_command(server_socket, cmd);
158
159                         //for (i=0; commands[i].func != NULL; ++i) {
160                         //if (!strncasecmp(cmd, commands[i].name, strlen(commands[i].name))) {
161                         //ret = (*commands[i].func) (server_socket, cmd);
162                         //}
163                         //}
164
165                 }
166
167                 free(cmd);
168         }
169 }
170
171
172 /*
173  * If you don't know what main() does by now you probably shouldn't be reading this code.
174  */
175 int main(int argc, char **argv)
176 {
177         int server_socket = 0;
178         char buf[1024];
179         int i;
180         char *ctdldir = CTDLDIR;
181         char cmd[1024] = { 0 };
182         int exitcode = 0;
183
184
185         int num_wows = sizeof(wows) / sizeof(struct wow);
186         int j;
187         for (i=0; i<num_wows; ++i) {
188                 printf("%s\n", wows[i].description);
189                 for (j=0; j<5; ++j) {
190                         printf("%d '%s'\n", j, wows[i].cmd[j]);
191                 }
192         }
193
194
195 exit(0);
196
197
198
199
200
201
202
203         for (i = 1; i < argc; ++i) {
204                 if (!strcmp(argv[i], "-h")) {
205                         ctdldir = argv[++i];
206                 } else {
207                         if (strlen(cmd) > 0) {
208                                 strcat(cmd, " ");
209                         }
210                         strcat(cmd, argv[i]);
211                 }
212         }
213
214         int is_interactive = ((strlen(cmd) == 0) ? 1 : 0);
215
216         if (is_interactive) {
217                 printf("\nCitadel administration shell (c) 2009-2017 by citadel.org\n"
218                        "This is open source software made available to you under the terms\n"
219                        "of the GNU General Public License v3.  All other rights reserved.\n");
220                 printf("Trying %s...\n", ctdldir);
221         }
222
223         sprintf(buf, "%s/citadel-admin.socket", ctdldir);
224         server_socket = uds_connectsock(buf);
225         if (server_socket < 0) {
226                 exit(1);
227         }
228
229         sock_getln(server_socket, buf, sizeof buf);
230         if (buf[0] == '2') {
231                 if (is_interactive) {
232                         printf("Connected: %s\n", buf);
233                         do_main_loop(server_socket);
234                 } else {
235                         exitcode = do_one_command(server_socket, cmd);
236                 }
237         }
238
239         sock_puts(server_socket, "QUIT");
240         sock_getln(server_socket, buf, sizeof buf);
241         if (is_interactive) {
242                 printf("%s\n", buf);
243         }
244         close(server_socket);
245         exit(exitcode);
246 }