Mailing list header changes (fuck you Google)
[citadel.git] / 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 int cmd_help(int sock, char *cmdbuf)
42 {
43         int i;
44
45         for (i = 0; commands[i].func != NULL; ++i) {
46                 printf("%-10s %s\n", commands[i].name, commands[i].doc);
47         }
48 }
49
50
51 /* Auto-completer function */
52 char *command_generator(const char *text, int state)
53 {
54         static int list_index;
55         static int len;
56         char *name;
57
58         if (!state) {
59                 list_index = 0;
60                 len = strlen(text);
61         }
62
63         while (name = commands[list_index].name) {
64                 ++list_index;
65
66                 if (!strncmp(name, text, len)) {
67                         return (strdup(name));
68                 }
69         }
70
71         return (NULL);
72 }
73
74
75 /* Auto-completer function */
76 char **ctdlsh_completion(const char *text, int start, int end)
77 {
78         char **matches = (char **) NULL;
79
80         rl_completer_word_break_characters = " ";
81         if (start == 0) {
82                 matches = rl_completion_matches(text, command_generator);
83         } else {
84                 rl_bind_key('\t', rl_abort);
85         }
86
87         return (matches);
88 }
89
90
91 int do_one_command(int server_socket, char *cmd)
92 {
93         int i;
94         int ret;
95         for (i = 0; commands[i].func != NULL; ++i) {
96                 if (!strncasecmp(cmd, commands[i].name, strlen(commands[i].name))) {
97                         ret = (*commands[i].func) (server_socket, cmd);
98                 }
99         }
100         return ret;
101 }
102
103
104 void do_main_loop(int server_socket)
105 {
106         char *cmd = NULL;
107         char prompt[1024];
108         char buf[1024];
109         char server_reply[1024];
110         int i;
111         int ret = (-1);
112
113         strcpy(prompt, "> ");
114
115         /* Do an INFO command and learn the hostname for the prompt */
116         sock_puts(server_socket, "INFO");
117         sock_getln(server_socket, buf, sizeof buf);
118         if (buf[0] == '1') {
119                 i = 0;
120                 while (sock_getln(server_socket, buf, sizeof buf), strcmp(buf, "000")) {
121                         if (i == 1) {
122                                 sprintf(prompt, "\n%s> ", buf);
123                         }
124                         ++i;
125                 }
126         }
127
128         /* Tell libreadline how we will help with auto-completion of commands */
129         rl_attempted_completion_function = ctdlsh_completion;
130
131         /* Here we go ... main command loop */
132         while ((ret != cmdret_exit) && (cmd = readline(prompt))) {
133
134                 if ((cmd) && (*cmd)) {
135                         add_history(cmd);
136                         ret = do_one_command(server_socket, cmd);
137
138                         //for (i=0; commands[i].func != NULL; ++i) {
139                         //if (!strncasecmp(cmd, commands[i].name, strlen(commands[i].name))) {
140                         //ret = (*commands[i].func) (server_socket, cmd);
141                         //}
142                         //}
143
144                 }
145
146                 free(cmd);
147         }
148 }
149
150
151 /*
152  * If you don't know what main() does by now you probably shouldn't be reading this code.
153  */
154 int main(int argc, char **argv)
155 {
156         int server_socket = 0;
157         char buf[1024];
158         int i;
159         char *ctdldir = CTDLDIR;
160         char cmd[1024] = { 0 };
161         int exitcode = 0;
162
163         for (i = 1; i < argc; ++i) {
164                 if (!strcmp(argv[i], "-h")) {
165                         ctdldir = argv[++i];
166                 } else {
167                         if (strlen(cmd) > 0) {
168                                 strcat(cmd, " ");
169                         }
170                         strcat(cmd, argv[i]);
171                 }
172         }
173
174         int is_interactive = ((strlen(cmd) == 0) ? 1 : 0);
175
176         if (is_interactive) {
177                 printf("\nCitadel administration shell (c) 2009-2017 by citadel.org\n"
178                        "This is open source software made available to you under the terms\n"
179                        "of the GNU General Public License v3.  All other rights reserved.\n");
180                 printf("Trying %s...\n", ctdldir);
181         }
182
183         sprintf(buf, "%s/citadel-admin.socket", ctdldir);
184         server_socket = uds_connectsock(buf);
185         if (server_socket < 0) {
186                 exit(1);
187         }
188
189         sock_getln(server_socket, buf, sizeof buf);
190         if (buf[0] == '2') {
191                 if (is_interactive) {
192                         printf("Connected: %s\n", buf);
193                         do_main_loop(server_socket);
194                 } else {
195                         exitcode = do_one_command(server_socket, cmd);
196                 }
197         }
198
199         sock_puts(server_socket, "QUIT");
200         sock_getln(server_socket, buf, sizeof buf);
201         if (is_interactive) {
202                 printf("%s\n", buf);
203         }
204         close(server_socket);
205         exit(exitcode);
206 }