Further improvements in pop3client: readline & history.
Showing
1 changed file
with
130 additions
and
10 deletions
... | @@ -50,6 +50,7 @@ | ... | @@ -50,6 +50,7 @@ |
50 | #include <mailutils/cctype.h> | 50 | #include <mailutils/cctype.h> |
51 | #include <mailutils/cstr.h> | 51 | #include <mailutils/cstr.h> |
52 | #include <mailutils/tls.h> | 52 | #include <mailutils/tls.h> |
53 | #include <mailutils/mutil.h> | ||
53 | 54 | ||
54 | /* A structure which contains information on the commands this program | 55 | /* A structure which contains information on the commands this program |
55 | can understand. */ | 56 | can understand. */ |
... | @@ -85,6 +86,7 @@ int com_user (int, char **); | ... | @@ -85,6 +86,7 @@ int com_user (int, char **); |
85 | int com_verbose (int, char **); | 86 | int com_verbose (int, char **); |
86 | int com_prompt (int, char **); | 87 | int com_prompt (int, char **); |
87 | int com_stls (int, char **); | 88 | int com_stls (int, char **); |
89 | int com_history (int, char **); | ||
88 | 90 | ||
89 | COMMAND *find_command (char *); | 91 | COMMAND *find_command (char *); |
90 | 92 | ||
... | @@ -131,6 +133,10 @@ COMMAND commands[] = { | ... | @@ -131,6 +133,10 @@ COMMAND commands[] = { |
131 | "send login: USER user" }, | 133 | "send login: USER user" }, |
132 | { "verbose", 1, 2, com_verbose, | 134 | { "verbose", 1, 2, com_verbose, |
133 | "Enable Protocol tracing: verbose [on|off]" }, | 135 | "Enable Protocol tracing: verbose [on|off]" }, |
136 | #ifdef WITH_READLINE | ||
137 | { "history", 1, 1, com_history, | ||
138 | "Show command history" }, | ||
139 | #endif | ||
134 | { NULL } | 140 | { NULL } |
135 | }; | 141 | }; |
136 | 142 | ||
... | @@ -210,6 +216,27 @@ expand_prompt () | ... | @@ -210,6 +216,27 @@ expand_prompt () |
210 | 216 | ||
211 | 217 | ||
212 | #ifdef WITH_READLINE | 218 | #ifdef WITH_READLINE |
219 | #define HISTFILE_SUFFIX "_history" | ||
220 | |||
221 | static char * | ||
222 | get_history_file_name () | ||
223 | { | ||
224 | static char *filename = NULL; | ||
225 | |||
226 | if (!filename) | ||
227 | { | ||
228 | char *hname; | ||
229 | |||
230 | hname = xmalloc(3 + strlen (rl_readline_name) + sizeof HISTFILE_SUFFIX); | ||
231 | strcpy (hname, "~/."); | ||
232 | strcat (hname, rl_readline_name); | ||
233 | strcat (hname, HISTFILE_SUFFIX); | ||
234 | filename = mu_tilde_expansion (hname, "/", NULL); | ||
235 | free(hname); | ||
236 | } | ||
237 | return filename; | ||
238 | } | ||
239 | |||
213 | /* Interface to Readline Completion */ | 240 | /* Interface to Readline Completion */ |
214 | 241 | ||
215 | char *command_generator (const char *, int); | 242 | char *command_generator (const char *, int); |
... | @@ -222,10 +249,18 @@ void | ... | @@ -222,10 +249,18 @@ void |
222 | initialize_readline () | 249 | initialize_readline () |
223 | { | 250 | { |
224 | /* Allow conditional parsing of the ~/.inputrc file. */ | 251 | /* Allow conditional parsing of the ~/.inputrc file. */ |
225 | rl_readline_name = (char *) "pop3"; | 252 | rl_readline_name = (char *) "pop3client"; |
226 | 253 | ||
227 | /* Tell the completer that we want a crack first. */ | 254 | /* Tell the completer that we want a crack first. */ |
228 | rl_attempted_completion_function = (CPPFunction *) pop_completion; | 255 | rl_attempted_completion_function = (CPPFunction *) pop_completion; |
256 | |||
257 | read_history (get_history_file_name ()); | ||
258 | } | ||
259 | |||
260 | void | ||
261 | finish_readline () | ||
262 | { | ||
263 | write_history (get_history_file_name()); | ||
229 | } | 264 | } |
230 | 265 | ||
231 | /* Attempt to complete on the contents of TEXT. START and END bound the | 266 | /* Attempt to complete on the contents of TEXT. START and END bound the |
... | @@ -280,12 +315,65 @@ command_generator (const char *text, int state) | ... | @@ -280,12 +315,65 @@ command_generator (const char *text, int state) |
280 | return NULL; | 315 | return NULL; |
281 | } | 316 | } |
282 | 317 | ||
283 | #else | 318 | static char *pre_input_line; |
284 | void | 319 | |
285 | initialize_readline () | 320 | static int |
321 | pre_input (void) | ||
322 | { | ||
323 | rl_insert_text (pre_input_line); | ||
324 | free (pre_input_line); | ||
325 | rl_pre_input_hook = NULL; | ||
326 | rl_redisplay (); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int | ||
331 | retrieve_history (char *str) | ||
332 | { | ||
333 | char *out; | ||
334 | int rc; | ||
335 | |||
336 | rc = history_expand (str, &out); | ||
337 | switch (rc) | ||
338 | { | ||
339 | case -1: | ||
340 | mu_error ("%s", out); | ||
341 | free (out); | ||
342 | return 1; | ||
343 | |||
344 | case 0: | ||
345 | break; | ||
346 | |||
347 | case 1: | ||
348 | pre_input_line = out; | ||
349 | rl_pre_input_hook = pre_input; | ||
350 | return 1; | ||
351 | |||
352 | case 2: | ||
353 | printf ("%s\n", out); | ||
354 | free (out); | ||
355 | return 1; | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | int | ||
361 | com_history (int argc, char **argv) | ||
286 | { | 362 | { |
363 | int i; | ||
364 | HIST_ENTRY **hlist; | ||
365 | |||
366 | hlist = history_list (); | ||
367 | for (i = 0; i < history_length; i++) | ||
368 | printf ("%4d) %s\n", i + 1, hlist[i]->line); | ||
369 | |||
370 | return 0; | ||
287 | } | 371 | } |
288 | 372 | ||
373 | #else | ||
374 | # define initialize_readline() | ||
375 | # define finish_readline() | ||
376 | |||
289 | char * | 377 | char * |
290 | readline (char *prompt) | 378 | readline (char *prompt) |
291 | { | 379 | { |
... | @@ -299,7 +387,7 @@ readline (char *prompt) | ... | @@ -299,7 +387,7 @@ readline (char *prompt) |
299 | 387 | ||
300 | if (!fgets (buf, sizeof (buf), stdin)) | 388 | if (!fgets (buf, sizeof (buf), stdin)) |
301 | return NULL; | 389 | return NULL; |
302 | return strdup (buf); | 390 | return xstrdup (buf); |
303 | } | 391 | } |
304 | 392 | ||
305 | void | 393 | void |
... | @@ -678,7 +766,7 @@ int | ... | @@ -678,7 +766,7 @@ int |
678 | com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | 766 | com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) |
679 | { | 767 | { |
680 | size_t count = 0; | 768 | size_t count = 0; |
681 | size_t size = 0; | 769 | mu_off_t size = 0; |
682 | int status = 0; | 770 | int status = 0; |
683 | 771 | ||
684 | status = mu_pop3_stat (pop3, &count, &size); | 772 | status = mu_pop3_stat (pop3, &count, &size); |
... | @@ -947,24 +1035,45 @@ com_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ... | @@ -947,24 +1035,45 @@ com_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) |
947 | } | 1035 | } |
948 | 1036 | ||
949 | 1037 | ||
1038 | static char * | ||
1039 | input_line_interactive () | ||
1040 | { | ||
1041 | char *p = expand_prompt (); | ||
1042 | char *line = readline (p); | ||
1043 | free (p); | ||
1044 | return line; | ||
1045 | } | ||
1046 | |||
1047 | static char * | ||
1048 | input_line_script () | ||
1049 | { | ||
1050 | size_t size = 0; | ||
1051 | char *buf = NULL; | ||
1052 | if (getline (&buf, &size, stdin) <= 0) | ||
1053 | return NULL; | ||
1054 | return buf; | ||
1055 | } | ||
1056 | |||
950 | int | 1057 | int |
951 | main (int argc MU_ARG_UNUSED, char **argv) | 1058 | main (int argc MU_ARG_UNUSED, char **argv) |
952 | { | 1059 | { |
953 | char *line, *s; | 1060 | char *line, *s; |
1061 | int interactive = isatty (0); | ||
1062 | char *(*input_line) () = interactive ? | ||
1063 | input_line_interactive : input_line_script; | ||
954 | 1064 | ||
955 | mu_set_program_name (argv[0]); | 1065 | mu_set_program_name (argv[0]); |
956 | prompt = strdup (DEFAULT_PROMPT); | 1066 | prompt = strdup (DEFAULT_PROMPT); |
1067 | if (interactive) | ||
957 | initialize_readline (); /* Bind our completer. */ | 1068 | initialize_readline (); /* Bind our completer. */ |
1069 | |||
958 | #ifdef WITH_TLS | 1070 | #ifdef WITH_TLS |
959 | mu_init_tls_libs (); | 1071 | mu_init_tls_libs (); |
960 | #endif | 1072 | #endif |
961 | /* Loop reading and executing lines until the user quits. */ | 1073 | /* Loop reading and executing lines until the user quits. */ |
962 | while (!done) | 1074 | while (!done) |
963 | { | 1075 | { |
964 | char *p = expand_prompt (); | 1076 | line = input_line (); |
965 | line = readline (p); | ||
966 | free (p); | ||
967 | |||
968 | if (!line) | 1077 | if (!line) |
969 | break; | 1078 | break; |
970 | 1079 | ||
... | @@ -976,7 +1085,16 @@ main (int argc MU_ARG_UNUSED, char **argv) | ... | @@ -976,7 +1085,16 @@ main (int argc MU_ARG_UNUSED, char **argv) |
976 | if (*s) | 1085 | if (*s) |
977 | { | 1086 | { |
978 | int status; | 1087 | int status; |
1088 | |||
1089 | #ifdef WITH_READLINE | ||
1090 | if (interactive) | ||
1091 | { | ||
1092 | if (retrieve_history (s)) | ||
1093 | continue; | ||
979 | add_history (s); | 1094 | add_history (s); |
1095 | } | ||
1096 | #endif | ||
1097 | |||
980 | status = execute_line (s); | 1098 | status = execute_line (s); |
981 | if (status != 0) | 1099 | if (status != 0) |
982 | mu_error ("Error: %s", mu_strerror (status)); | 1100 | mu_error ("Error: %s", mu_strerror (status)); |
... | @@ -984,6 +1102,8 @@ main (int argc MU_ARG_UNUSED, char **argv) | ... | @@ -984,6 +1102,8 @@ main (int argc MU_ARG_UNUSED, char **argv) |
984 | 1102 | ||
985 | free (line); | 1103 | free (line); |
986 | } | 1104 | } |
1105 | if (interactive) | ||
1106 | finish_readline (); | ||
987 | exit (0); | 1107 | exit (0); |
988 | } | 1108 | } |
989 | 1109 | ... | ... |
-
Please register or sign in to post a comment