Commit 9f726ee0 9f726ee08feeefd295bd5b2e3f6c676d2248f3f5 by Sergey Poznyakoff

mail: Implement folder completion in "save"

* mail/mailline.c (file_compl_internal): New function (from file_compl);
(file_compl): Call file_compl_internal.
(msglist_file_compl): Call file_compl_internal.
1 parent b4d7b1a6
...@@ -121,7 +121,7 @@ ml_readline_internal () ...@@ -121,7 +121,7 @@ ml_readline_internal ()
121 char *buf = NULL; 121 char *buf = NULL;
122 size_t size = 0, n; 122 size_t size = 0, n;
123 int rc; 123 int rc;
124 124
125 rc = mu_stream_getline (mu_strin, &buf, &size, &n); 125 rc = mu_stream_getline (mu_strin, &buf, &size, &n);
126 if (rc) 126 if (rc)
127 { 127 {
...@@ -200,7 +200,7 @@ ml_command_completion (char *cmd, int start, int end) ...@@ -200,7 +200,7 @@ ml_command_completion (char *cmd, int start, int end)
200 char **ret; 200 char **ret;
201 char *p; 201 char *p;
202 struct mu_wordsplit ws; 202 struct mu_wordsplit ws;
203 203
204 for (p = rl_line_buffer; p < rl_line_buffer + start && mu_isblank (*p); p++) 204 for (p = rl_line_buffer; p < rl_line_buffer + start && mu_isblank (*p); p++)
205 ; 205 ;
206 206
...@@ -211,7 +211,7 @@ ml_command_completion (char *cmd, int start, int end) ...@@ -211,7 +211,7 @@ ml_command_completion (char *cmd, int start, int end)
211 return NULL; 211 return NULL;
212 } 212 }
213 rl_completion_append_character = ' '; 213 rl_completion_append_character = ' ';
214 214
215 if (ws.ws_wordc == 0 || 215 if (ws.ws_wordc == 0 ||
216 (ws.ws_wordc == 1 && strlen (ws.ws_wordv[0]) <= end - start)) 216 (ws.ws_wordc == 1 && strlen (ws.ws_wordv[0]) <= end - start))
217 { 217 {
...@@ -241,7 +241,7 @@ ml_command_generator (const char *text, int state) ...@@ -241,7 +241,7 @@ ml_command_generator (const char *text, int state)
241 static int i, len; 241 static int i, len;
242 const char *name; 242 const char *name;
243 const struct mail_command *cp; 243 const struct mail_command *cp;
244 244
245 if (!state) 245 if (!state)
246 { 246 {
247 i = 0; 247 i = 0;
...@@ -291,14 +291,6 @@ msglist_compl (int argc, char **argv, int ws) ...@@ -291,14 +291,6 @@ msglist_compl (int argc, char **argv, int ws)
291 } 291 }
292 292
293 char ** 293 char **
294 msglist_file_compl (int argc, char **argv, int ws MU_ARG_UNUSED)
295 {
296 if (argc == 1)
297 ml_attempted_completion_over ();
298 return NULL;
299 }
300
301 char **
302 command_compl (int argc, char **argv, int ws) 294 command_compl (int argc, char **argv, int ws)
303 { 295 {
304 ml_set_completion_append_character (0); 296 ml_set_completion_append_character (0);
...@@ -313,24 +305,24 @@ command_compl (int argc, char **argv, int ws) ...@@ -313,24 +305,24 @@ command_compl (int argc, char **argv, int ws)
313 305
314 Select only those files that match given FLAGS (MU_FOLDER_ATTRIBUTE_* 306 Select only those files that match given FLAGS (MU_FOLDER_ATTRIBUTE_*
315 constants). 307 constants).
316 308
317 STATE is 0 for the first call, 1 otherwise. 309 STATE is 0 for the first call, 1 otherwise.
318 */ 310 */
319 static char * 311 static char *
320 file_generator (const char *text, int state, 312 file_generator (const char *text, int state,
321 char *path, size_t pathlen, 313 char *path, size_t pathlen,
322 char repl, 314 char repl,
323 int flags) 315 int flags)
324 { 316 {
325 static mu_list_t list; 317 static mu_list_t list;
326 static mu_iterator_t itr; 318 static mu_iterator_t itr;
327 319
328 if (!state) 320 if (!state)
329 { 321 {
330 char *wcard; 322 char *wcard;
331 mu_folder_t folder; 323 mu_folder_t folder;
332 size_t count; 324 size_t count;
333 325
334 wcard = xmalloc (strlen (text) + 2); 326 wcard = xmalloc (strlen (text) + 2);
335 strcat (strcpy (wcard, text), "*"); 327 strcat (strcpy (wcard, text), "*");
336 328
...@@ -339,7 +331,7 @@ file_generator (const char *text, int state, ...@@ -339,7 +331,7 @@ file_generator (const char *text, int state,
339 free (wcard); 331 free (wcard);
340 return NULL; 332 return NULL;
341 } 333 }
342 334
343 mu_folder_list (folder, path, wcard, 1, &list); 335 mu_folder_list (folder, path, wcard, 1, &list);
344 free (wcard); 336 free (wcard);
345 mu_folder_destroy (&folder); 337 mu_folder_destroy (&folder);
...@@ -351,7 +343,7 @@ file_generator (const char *text, int state, ...@@ -351,7 +343,7 @@ file_generator (const char *text, int state,
351 } 343 }
352 else if (count == 1) 344 else if (count == 1)
353 ml_set_completion_append_character (0); 345 ml_set_completion_append_character (0);
354 346
355 if (mu_list_get_iterator (list, &itr)) 347 if (mu_list_get_iterator (list, &itr))
356 { 348 {
357 mu_list_destroy (&list); 349 mu_list_destroy (&list);
...@@ -372,7 +364,7 @@ file_generator (const char *text, int state, ...@@ -372,7 +364,7 @@ file_generator (const char *text, int state,
372 { 364 {
373 size_t len = strlen (resp->name + pathlen); 365 size_t len = strlen (resp->name + pathlen);
374 char *ptr; 366 char *ptr;
375 367
376 ret = xmalloc (len + (repl ? 1 : 0) + 1); 368 ret = xmalloc (len + (repl ? 1 : 0) + 1);
377 ptr = ret; 369 ptr = ret;
378 if (repl) 370 if (repl)
...@@ -395,13 +387,13 @@ folder_generator (const char *text, int state) ...@@ -395,13 +387,13 @@ folder_generator (const char *text, int state)
395 { 387 {
396 char *ret; 388 char *ret;
397 static size_t pathlen; 389 static size_t pathlen;
398 390
399 if (!state) 391 if (!state)
400 { 392 {
401 char *path = util_folder_path (""); 393 char *path = util_folder_path ("");
402 if (!path) 394 if (!path)
403 return NULL; 395 return NULL;
404 396
405 pathlen = strlen (path); 397 pathlen = strlen (path);
406 ret = file_generator (text, state, path, pathlen, '+', 398 ret = file_generator (text, state, path, pathlen, '+',
407 MU_FOLDER_ATTRIBUTE_ALL); 399 MU_FOLDER_ATTRIBUTE_ALL);
...@@ -413,8 +405,102 @@ folder_generator (const char *text, int state) ...@@ -413,8 +405,102 @@ folder_generator (const char *text, int state)
413 return ret; 405 return ret;
414 } 406 }
415 407
416 char ** 408 static char *
417 file_compl (int argc, char **argv, int ws) 409 msgtype_generator (const char *text, int state)
410 {
411 static char types[] = "dnorTtu";
412 static int i;
413 char *s;
414
415 if (!state)
416 {
417 if (text[1])
418 return NULL;
419 i = 0;
420 }
421 if (!types[i])
422 return NULL;
423 s = malloc (2);
424 if (s)
425 {
426 s[0] = types[i++];
427 s[1] = 0;
428 }
429 return s;
430 }
431
432 static char *
433 header_generator (const char *text, int state)
434 {
435 static int i, len;
436 char *hdr;
437 char *hdrlist[] = {
438 MU_HEADER_RETURN_PATH,
439 MU_HEADER_RECEIVED,
440 MU_HEADER_DATE,
441 MU_HEADER_DCC,
442 MU_HEADER_FROM,
443 MU_HEADER_SENDER,
444 MU_HEADER_RESENT_FROM,
445 MU_HEADER_SUBJECT,
446 MU_HEADER_RESENT_SENDER,
447 MU_HEADER_TO,
448 MU_HEADER_RESENT_TO,
449 MU_HEADER_CC,
450 MU_HEADER_RESENT_CC,
451 MU_HEADER_BCC,
452 MU_HEADER_RESENT_BCC,
453 MU_HEADER_REPLY_TO,
454 MU_HEADER_RESENT_REPLY_TO,
455 MU_HEADER_MESSAGE_ID,
456 MU_HEADER_RESENT_MESSAGE_ID,
457 MU_HEADER_IN_REPLY_TO,
458 MU_HEADER_REFERENCE,
459 MU_HEADER_REFERENCES,
460 MU_HEADER_ENCRYPTED,
461 MU_HEADER_PRECEDENCE,
462 MU_HEADER_STATUS,
463 MU_HEADER_CONTENT_LENGTH,
464 MU_HEADER_CONTENT_LANGUAGE,
465 MU_HEADER_CONTENT_TRANSFER_ENCODING,
466 MU_HEADER_CONTENT_ID,
467 MU_HEADER_CONTENT_TYPE,
468 MU_HEADER_CONTENT_DESCRIPTION,
469 MU_HEADER_CONTENT_DISPOSITION,
470 MU_HEADER_CONTENT_MD5,
471 MU_HEADER_CONTENT_LOCATION,
472 MU_HEADER_MIME_VERSION,
473 MU_HEADER_X_MAILER,
474 MU_HEADER_X_UIDL,
475 MU_HEADER_X_UID,
476 MU_HEADER_X_IMAPBASE,
477 MU_HEADER_ENV_SENDER,
478 MU_HEADER_ENV_DATE,
479 MU_HEADER_FCC,
480 MU_HEADER_DELIVERY_DATE,
481 MU_HEADER_ENVELOPE_TO,
482 MU_HEADER_X_EXPIRE_TIMESTAMP,
483 NULL
484 };
485
486 if (!state)
487 {
488 i = 0;
489 len = strlen (text);
490 }
491
492 while ((hdr = hdrlist[i]))
493 {
494 i++;
495 if (mu_c_strncasecmp (hdr, text, len) == 0)
496 return strdup (hdr);
497 }
498
499 return NULL;
500 }
501
502 static char **
503 file_compl_internal (int argc, char **argv, int ws, int msglist)
418 { 504 {
419 char *text; 505 char *text;
420 506
...@@ -424,26 +510,59 @@ file_compl (int argc, char **argv, int ws) ...@@ -424,26 +510,59 @@ file_compl (int argc, char **argv, int ws)
424 ml_attempted_completion_over (); 510 ml_attempted_completion_over ();
425 return NULL; 511 return NULL;
426 } 512 }
427 513
428 text = argv[argc-1]; 514 text = argv[argc-1];
515
516 if (msglist)
517 {
518 if (text[0] == ':')
519 {
520 ml_set_completion_append_character (' ');
521 return rl_completion_matches (text, msgtype_generator);
522 }
523 else if (mu_isalpha (text[0]))
524 {
525 ml_set_completion_append_character (':');
526 return rl_completion_matches (text, header_generator);
527 }
528 else if (mu_isdigit (text[0]))
529 {
530 ml_attempted_completion_over ();
531 return NULL;
532 }
533 }
534
429 switch (text[0]) 535 switch (text[0])
430 { 536 {
431 case '+': 537 case '+':
432 text++; 538 text++;
433 break; 539 break;
434 540
541 case '%':
435 case '#': 542 case '#':
436 case '&': 543 case '&':
437 ml_attempted_completion_over (); 544 ml_attempted_completion_over ();
438 return NULL; 545 return NULL;
439 546
440 default: 547 default:
441 return NULL; /* Will be expanded by readline itself */ 548 return NULL; /* Will be expanded by readline itself */
442 } 549 }
443 550
444 return rl_completion_matches (text, folder_generator); 551 return rl_completion_matches (text, folder_generator);
445 } 552 }
446 553
554 char **
555 file_compl (int argc, char **argv, int ws)
556 {
557 return file_compl_internal (argc, argv, ws, 0);
558 }
559
560 char **
561 msglist_file_compl (int argc, char **argv, int ws)
562 {
563 return file_compl_internal (argc, argv, ws, 1);
564 }
565
447 static char * 566 static char *
448 dir_generator (const char *text, int state) 567 dir_generator (const char *text, int state)
449 { 568 {
...@@ -479,13 +598,13 @@ dir_generator (const char *text, int state) ...@@ -479,13 +598,13 @@ dir_generator (const char *text, int state)
479 pathlen = 0; 598 pathlen = 0;
480 repl = 0; 599 repl = 0;
481 break; 600 break;
482 601
483 default: 602 default:
484 path = strdup ("./"); 603 path = strdup ("./");
485 pathlen = 2; 604 pathlen = 2;
486 repl = 0; 605 repl = 0;
487 } 606 }
488 607
489 ret = file_generator (text, state, path, pathlen, repl, 608 ret = file_generator (text, state, path, pathlen, repl,
490 MU_FOLDER_ATTRIBUTE_DIRECTORY); 609 MU_FOLDER_ATTRIBUTE_DIRECTORY);
491 free (path); 610 free (path);
...@@ -513,7 +632,7 @@ alias_generator (const char *text, int state) ...@@ -513,7 +632,7 @@ alias_generator (const char *text, int state)
513 { 632 {
514 static alias_iterator_t itr; 633 static alias_iterator_t itr;
515 const char *p; 634 const char *p;
516 635
517 if (!state) 636 if (!state)
518 p = alias_iterate_first (text, &itr); 637 p = alias_iterate_first (text, &itr);
519 else 638 else
...@@ -557,7 +676,7 @@ exec_generator (const char *text, int state) ...@@ -557,7 +676,7 @@ exec_generator (const char *text, int state)
557 static size_t dsize; 676 static size_t dsize;
558 static DIR *dp; 677 static DIR *dp;
559 struct dirent *ent; 678 struct dirent *ent;
560 679
561 if (!state) 680 if (!state)
562 { 681 {
563 var = getenv ("PATH"); 682 var = getenv ("PATH");
...@@ -580,13 +699,13 @@ exec_generator (const char *text, int state) ...@@ -580,13 +699,13 @@ exec_generator (const char *text, int state)
580 break; 699 break;
581 else 700 else
582 var++; 701 var++;
583 702
584 p = strchr (var, ':'); 703 p = strchr (var, ':');
585 if (!p) 704 if (!p)
586 len = strlen (var) + 1; 705 len = strlen (var) + 1;
587 else 706 else
588 len = p - var + 1; 707 len = p - var + 1;
589 708
590 if (dsize == 0) 709 if (dsize == 0)
591 { 710 {
592 dir = malloc (len); 711 dir = malloc (len);
...@@ -597,13 +716,13 @@ exec_generator (const char *text, int state) ...@@ -597,13 +716,13 @@ exec_generator (const char *text, int state)
597 dir = realloc (dir, len); 716 dir = realloc (dir, len);
598 dsize = len; 717 dsize = len;
599 } 718 }
600 719
601 if (!dir) 720 if (!dir)
602 return NULL; 721 return NULL;
603 memcpy (dir, var, len - 1); 722 memcpy (dir, var, len - 1);
604 dir[len - 1] = 0; 723 dir[len - 1] = 0;
605 var += len - 1; 724 var += len - 1;
606 725
607 dp = opendir (dir); 726 dp = opendir (dir);
608 if (!dp) 727 if (!dp)
609 continue; 728 continue;
...@@ -614,13 +733,13 @@ exec_generator (const char *text, int state) ...@@ -614,13 +733,13 @@ exec_generator (const char *text, int state)
614 char *name = mkfilename (dir, ent->d_name); 733 char *name = mkfilename (dir, ent->d_name);
615 if (name) 734 if (name)
616 { 735 {
617 int rc = access (name, X_OK); 736 int rc = access (name, X_OK);
618 if (rc == 0) 737 if (rc == 0)
619 { 738 {
620 struct stat st; 739 struct stat st;
621 rc = !(stat (name, &st) == 0 && S_ISREG (st.st_mode)); 740 rc = !(stat (name, &st) == 0 && S_ISREG (st.st_mode));
622 } 741 }
623 742
624 free (name); 743 free (name);
625 if (rc == 0 744 if (rc == 0
626 && strlen (ent->d_name) >= prefix_len 745 && strlen (ent->d_name) >= prefix_len
...@@ -944,4 +1063,3 @@ ml_attempted_completion_over () ...@@ -944,4 +1063,3 @@ ml_attempted_completion_over ()
944 } 1063 }
945 1064
946 #endif 1065 #endif
947
......