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