Commit 69f7dcae 69f7dcae5a906acc9126ca25e33881cba944f85d by Sergey Poznyakoff

Further improvements in pop3client: readline & history.

1 parent b9355608
...@@ -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
......