Added a shutdown command to ctdlsh
[citadel.git] / ctdlsh / src / main.c
1 /*
2  * (c) 2009-2011 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
10
11 int cmd_quit(int sock, char *cmdbuf) {
12         return(cmdret_exit);
13 }
14
15
16 /*
17  * Commands understood by ctdlsh
18  */
19 typedef struct {
20         char *name;
21         ctdlsh_cmdfunc_t *func;
22         char *doc;
23 } COMMAND;
24
25 COMMAND commands[] = {
26         {       "?",            cmd_help,       "Display this message"                  },
27         {       "help",         cmd_help,       "Display this message"                  },
28         {       "quit",         cmd_quit,       "Quit using ctdlsh"                     },
29         {       "exit",         cmd_quit,       "Quit using ctdlsh"                     },
30         {       "date",         cmd_datetime,   "Print the server's date and time"      },
31         {       "time",         cmd_datetime,   "Print the server's date and time"      },
32         {       "passwd",       cmd_passwd,     "Set or change an account password"     },
33         {       "shutdown",     cmd_shutdown,   "Shut down the Citadel server"          },
34         {       NULL,           NULL,           NULL                                    }
35 };
36
37
38 int cmd_help(int sock, char *cmdbuf) {
39         int i;
40
41         for (i=0; commands[i].func != NULL; ++i) {
42                 printf("%-10s %s\n", commands[i].name, commands[i].doc);
43         }
44 }
45
46
47
48
49
50
51 int discover_ipgm_secret(char *dirname) {
52         int fd;
53         struct partial_config ccc;
54         char configfile[1024];
55
56         sprintf(configfile, "%s/citadel.config", dirname);
57         fd = open(configfile, O_RDONLY);
58         if (fd < 0) {
59                 fprintf(stderr, "%s: %s\n", configfile, strerror(errno));
60                 return(-1);
61         }
62
63         if (read(fd, &ccc, sizeof(struct partial_config)) != sizeof(struct partial_config)) {
64                 fprintf(stderr, "%s: %s\n", configfile, strerror(errno));
65                 return(-1);
66         }
67         if (close(fd) != 0) {
68                 fprintf(stderr, "%s: %s\n", configfile, strerror(errno));
69                 return(-1);
70         }
71         return(ccc.c_ipgm_secret);
72 }
73
74
75 /* Auto-completer function */
76 char *command_generator(const char *text, int state) {
77         static int list_index;
78         static int len;
79         char *name;
80
81         if (!state) {
82                 list_index = 0;
83                 len = strlen(text);
84         }
85
86         while (name = commands[list_index].name) {
87                 ++list_index;
88
89                 if (!strncmp(name, text, len)) {
90                         return(strdup(name));
91                 }
92         }
93
94         return(NULL);
95 }
96
97
98 /* Auto-completer function */
99 char **ctdlsh_completion(const char *text, int start, int end) {
100         char **matches = (char **) NULL;
101
102         if (start == 0) {
103                 matches = rl_completion_matches(text, command_generator);
104         }
105         else {
106                 rl_bind_key('\t', rl_abort);
107         }
108
109         return (matches);
110 }
111
112
113
114 void do_main_loop(int server_socket) {
115         char *cmd = NULL;
116         char prompt[1024];
117         char buf[1024];
118         char server_reply[1024];
119         int i;
120         int ret = (-1);
121
122         strcpy(prompt, "> ");
123
124         /* Do an INFO command and learn the hostname for the prompt */
125         sock_puts(server_socket, "INFO");
126         sock_getln(server_socket, buf, sizeof buf);
127         if (buf[0] == '1') {
128                 i = 0;
129                 while(sock_getln(server_socket, buf, sizeof buf), strcmp(buf, "000")) {
130                         if (i == 1) {
131                                 sprintf(prompt, "\n%s> ", buf);
132                         }
133                         ++i;
134                 }
135         }
136
137         /* Tell libreadline how we will help with auto-completion of commands */
138         rl_attempted_completion_function = ctdlsh_completion;
139
140         /* Here we go ... main command loop */
141         while ((ret != cmdret_exit) && (cmd = readline(prompt))) {
142
143                 if ((cmd) && (*cmd)) {
144                         add_history(cmd);
145
146                         for (i=0; commands[i].func != NULL; ++i) {
147                                 if (!strncasecmp(cmd, commands[i].name, strlen(commands[i].name))) {
148                                         ret = (*commands[i].func) (server_socket, cmd);
149                                 }
150                         }
151
152                 }
153
154                 free(cmd);
155         }
156 }
157
158 int main(int argc, char **argv)
159 {
160         int server_socket = 0;
161         char buf[1024];
162         int ipgm_secret = (-1);
163         int c;
164         char *ctdldir = CTDLDIR;
165
166         printf("\nCitadel administration shell v" PACKAGE_VERSION "\n");
167         printf("(c) 2009-2011 citadel.org GPLv3\n");
168
169         opterr = 0;
170         while ((c = getopt (argc, argv, "h:")) != -1) {
171                 switch(c) {
172                 case 'h':
173                         ctdldir = optarg;
174                         break;
175                 case '?':
176                         if (optopt == 'h') {
177                                 fprintf(stderr, "Option -%c requires an argument\n", optopt);
178                         }
179                         else {
180                                 fprintf(stderr, "Unknown option '-%c'\n", optopt);
181                                 fprintf(stderr, "usage: %s [-h citadel_dir]\n", argv[0]);
182                         }
183                         exit(1);
184                 }
185         }
186
187         ipgm_secret = discover_ipgm_secret(ctdldir);
188         if (ipgm_secret < 0) {
189                 exit(1);
190         }
191
192         printf("Trying %s...\n", ctdldir);
193         sprintf(buf, "%s/citadel.socket", ctdldir);
194         server_socket = uds_connectsock(buf);
195         if (server_socket < 0) {
196                 exit(1);
197         }
198
199         sock_getln(server_socket, buf, sizeof buf);
200         printf("%s\n", buf);
201
202         sock_printf(server_socket, "IPGM %d\n", ipgm_secret);
203         sock_getln(server_socket, buf, sizeof buf);
204         printf("%s\n", buf);
205
206         if (buf[0] == '2') {
207                 do_main_loop(server_socket);
208         }
209
210         sock_puts(server_socket, "QUIT");
211         sock_getln(server_socket, buf, sizeof buf);
212         printf("%s\n", buf);
213         close(server_socket);
214         exit(0);
215 }