6fc29315c51ab7d35cc5f1ae3f16297689e7dffe
[citadel.git] / ctdlsh / main.c
1 /*
2  * (c) 2009-2012 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         return(cmdret_exit);
11 }
12
13
14 /*
15  * Commands understood by ctdlsh
16  */
17 typedef struct {
18         char *name;
19         ctdlsh_cmdfunc_t *func;
20         char *doc;
21 } COMMAND;
22
23 COMMAND commands[] = {
24         {       "?",            cmd_help,       "Display this message"                  },
25         {       "help",         cmd_help,       "Display this message"                  },
26         {       "date",         cmd_datetime,   "Print the server's date and time"      },
27         {       "config",       cmd_config,     "Configure the Citadel server"          },
28         {       "export",       cmd_export,     "Export all Citadel databases"          },
29         {       "shutdown",     cmd_shutdown,   "Shut down the Citadel server"          },
30         {       "time",         cmd_datetime,   "Print the server's date and time"      },
31         {       "passwd",       cmd_passwd,     "Set or change an account password"     },
32         {       "who",          cmd_who,        "Display a list of online users"        },
33         {       "exit",         cmd_quit,       "Quit using ctdlsh"                     },
34         {       "quit",         cmd_quit,       "Quit using ctdlsh"                     },
35         {       NULL,           NULL,           NULL                                    }
36 };
37
38
39 int cmd_help(int sock, char *cmdbuf) {
40         int i;
41
42         for (i=0; commands[i].func != NULL; ++i) {
43                 printf("%-10s %s\n", commands[i].name, commands[i].doc);
44         }
45 }
46
47
48 /* Auto-completer function */
49 char *command_generator(const char *text, int state) {
50         static int list_index;
51         static int len;
52         char *name;
53
54         if (!state) {
55                 list_index = 0;
56                 len = strlen(text);
57         }
58
59         while (name = commands[list_index].name) {
60                 ++list_index;
61
62                 if (!strncmp(name, text, len)) {
63                         return(strdup(name));
64                 }
65         }
66
67         return(NULL);
68 }
69
70
71 /* Auto-completer function */
72 char **ctdlsh_completion(const char *text, int start, int end) {
73         char **matches = (char **) NULL;
74
75         if (start == 0) {
76                 matches = rl_completion_matches(text, command_generator);
77         }
78         else {
79                 rl_bind_key('\t', rl_abort);
80         }
81
82         return (matches);
83 }
84
85
86 void do_main_loop(int server_socket) {
87         char *cmd = NULL;
88         char prompt[1024];
89         char buf[1024];
90         char server_reply[1024];
91         int i;
92         int ret = (-1);
93
94         strcpy(prompt, "> ");
95
96         /* Do an INFO command and learn the hostname for the prompt */
97         sock_puts(server_socket, "INFO");
98         sock_getln(server_socket, buf, sizeof buf);
99         if (buf[0] == '1') {
100                 i = 0;
101                 while(sock_getln(server_socket, buf, sizeof buf), strcmp(buf, "000")) {
102                         if (i == 1) {
103                                 sprintf(prompt, "\n%s> ", buf);
104                         }
105                         ++i;
106                 }
107         }
108
109         /* Tell libreadline how we will help with auto-completion of commands */
110         rl_attempted_completion_function = ctdlsh_completion;
111
112         /* Here we go ... main command loop */
113         while ((ret != cmdret_exit) && (cmd = readline(prompt))) {
114
115                 if ((cmd) && (*cmd)) {
116                         add_history(cmd);
117
118                         for (i=0; commands[i].func != NULL; ++i) {
119                                 if (!strncasecmp(cmd, commands[i].name, strlen(commands[i].name))) {
120                                         ret = (*commands[i].func) (server_socket, cmd);
121                                 }
122                         }
123
124                 }
125
126                 free(cmd);
127         }
128 }
129
130
131 /*
132  * If you don't know what main() does by now you probably shouldn't be reading this code.
133  */
134 int main(int argc, char **argv)
135 {
136         int server_socket = 0;
137         char buf[1024];
138         int c;
139         char *ctdldir = CTDLDIR;
140
141         printf("\nCitadel administration shell (c) 2009-2016 by citadel.org\n"
142                 "This is open source software made available to you under the terms\n"
143                 "of the GNU General Public License v3.  All other rights reserved.\n"
144         );
145
146         opterr = 0;
147         while ((c = getopt (argc, argv, "h:")) != -1) {
148                 switch(c) {
149                 case 'h':
150                         ctdldir = optarg;
151                         break;
152                 case '?':
153                         if (optopt == 'h') {
154                                 fprintf(stderr, "Option -%c requires an argument\n", optopt);
155                         }
156                         else {
157                                 fprintf(stderr, "Unknown option '-%c'\n", optopt);
158                                 fprintf(stderr, "usage: %s [-h citadel_dir]\n", argv[0]);
159                         }
160                         exit(1);
161                 }
162         }
163
164         printf("Trying %s...\n", ctdldir);
165         sprintf(buf, "%s/citadel-admin.socket", ctdldir);
166         server_socket = uds_connectsock(buf);
167         if (server_socket < 0) {
168                 exit(1);
169         }
170
171         sock_getln(server_socket, buf, sizeof buf);
172         if (buf[0] == '2') {
173                 printf("Connected: %s\n", buf);
174                 do_main_loop(server_socket);
175         }
176
177         sock_puts(server_socket, "QUIT");
178         sock_getln(server_socket, buf, sizeof buf);
179         printf("%s\n", buf);
180         close(server_socket);
181         exit(0);
182 }