4 * by JH <jheinonen@bigfoot.com>
6 * Copyright (C) 1999, 2000 Jaakko Heinonen
15 #include "abook_curses.h"
19 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
25 # ifdef HAVE_LINUX_TERMIOS_H
26 # include <linux/termios.h>
29 #ifdef HAVE_SYS_IOCTL_H
30 # include <sys/ioctl.h>
42 static void init_abook();
43 static void set_filenames();
44 static void free_filenames();
45 static void display_help(char **tbl);
46 static void get_commands();
47 static void parse_command_line(int argc, char **argv);
48 static void show_usage();
49 static void mutt_query(char *str);
50 static void init_mutt_query();
51 static void quit_mutt_query();
52 static void launch_mutt();
53 static void launch_lynx();
54 static void win_changed(int dummy);
55 static void open_datafile();
57 static void resize_abook();
59 static void convert(char *srcformat, char *srcfile,
60 char *dstformat, char *dstfile);
62 int should_resize = FALSE;
63 int can_resize = FALSE;
65 char *datafile = NULL;
68 WINDOW *top = NULL, *bottom = NULL;
73 top = newwin(LIST_TOP - 1, COLS, 0, 0);
75 bottom = newwin(LINES - LIST_BOTTOM, COLS, LIST_BOTTOM, 0);
91 initscr(); cbreak(); noecho();
93 intrflush(stdscr, FALSE);
96 fprintf(stderr, "init_abook():\n");
97 fprintf(stderr, " COLS = %d, LINES = %d\n", COLS, LINES);
99 if( LINES < MIN_LINES || COLS < MIN_COLS ) {
100 clear(); refresh(); endwin();
101 fprintf(stderr, "Your terminal size is %dx%d\n", COLS, LINES);
102 fprintf(stderr, "Terminal is too small. Minium terminal size "
104 "%dx%d\n", MIN_COLS, MIN_LINES);
107 umask(DEFAULT_UMASK);
109 signal(SIGWINCH, win_changed);
111 signal(SIGINT, quit_abook);
112 signal(SIGKILL, quit_abook);
113 signal(SIGTERM, quit_abook);
119 * this is very ugly for now
121 /*if( options_get_int("datafile", "autosave") )*/
123 if( load_database(datafile) == 2 ) {
124 char *tmp = strconcat(getenv("HOME"),
127 if( safe_strcmp(tmp, datafile) ) {
129 statusline_msg("Sorry, the specified file does "
130 "not appear to be a valid abook addressbook");
131 statusline_msg("Will open default addressbook...");
134 load_database(datafile);
145 if( options_get_int("autosave") )
148 statusline_addstr("Save database (y/N)");
168 main(int argc, char **argv)
170 #if defined(HAVE_SETLOCALE) && defined(HAVE_LOCALE_H)
171 setlocale(LC_ALL, "" );
174 parse_command_line(argc, argv);
190 if( (stat(getenv("HOME"), &s)) == -1 || ! S_ISDIR(s.st_mode) ) {
191 fprintf(stderr,"%s is not a valid HOME directory\n", getenv("HOME") );
196 datafile = strconcat(getenv("HOME"), "/" DATAFILE, NULL);
198 rcfile = strconcat(getenv("HOME"), "/" RCFILE, NULL);
200 atexit(free_filenames);
211 headerline(char *str)
215 mvwhline(top, 1, 0, ACS_HLINE, COLS);
217 mvwprintw(top, 0, 0, "%s | %s", PACKAGE " " VERSION, str);
228 if( should_resize ) {
235 refresh_statusline();
236 headerline(MAIN_HELPLINE);
244 extern list_item *database;
250 fprintf(stderr,"sizeof(list_item) = %d\n", sizeof(list_item));
251 fprintf(stderr,"--- dumping item %d ---\n", curitem);
253 for(i=0; i<ITEM_FIELDS; i++)
254 fprintf(stderr,"%d - %d\n",
255 i, (int)database[curitem][i]);
257 fprintf(stderr,"--- end of dump ---\n");
262 extern char *selected;
271 can_resize = TRUE; /* it's safe to resize now */
277 can_resize = FALSE; /* it's not safe to resize anymore */
280 case '?': display_help(mainhelp); break;
281 case 'a': add_item(); break;
282 case '\r': edit_item(-1); break;
285 case 'r': remove_items(); break;
286 case 12: refresh_screen(); break;
289 case KEY_UP: scroll_up(); break;
291 case KEY_DOWN: scroll_down(); break;
293 case KEY_PPAGE: page_up(); break;
295 case KEY_NPAGE: page_down(); break;
298 case KEY_HOME: goto_home(); break;
300 case KEY_END: goto_end(); break;
302 case 'w': save_database();
304 case 'l': read_database(); break;
305 case 'i': import_database(); break;
306 case 'e': export_database(); break;
307 case 'C': clear_database(); break;
309 case 'y': edit_options(); break;
310 case 'o': open_datafile(); break;
312 case 's': sort_database(); break;
313 case 'S': sort_surname(); break;
315 case '/': find(0); break;
316 case '\\': find(1); break;
318 case ' ': if(curitem >= 0) {
319 selected[curitem] = !selected[curitem];
320 print_number_of_items();
324 case '+': select_all();
327 case '-': select_none();
330 case '*': invert_selection();
333 case 'A': move_curitem(MOVE_ITEM_UP);
335 case 'Z': move_curitem(MOVE_ITEM_DOWN);
338 case 'm': launch_mutt(); break;
340 case 'p': print_database(); break;
342 case 'u': launch_lynx(); break;
344 case 'D': dump_item();
352 display_help(char **tbl)
358 refresh_statusline();
360 for( i = 0; tbl[i] != NULL; i++) {
361 mvaddstr(j++, 0, tbl[i]);
362 if( ( !( (i+1) % (LINES-7) ) ) ||
363 (tbl[i+1] == NULL) ) {
365 statusline_msg("Press any key to continue...");
367 refresh_statusline();
376 display_editor_help(WINDOW *w)
382 headerline("editor help");
384 for( i = 0; editorhelp[i] != NULL; i++) {
385 waddstr(w, editorhelp[i]);
386 if( ( !( (i+1) % (LINES-8) ) ) ||
387 (editorhelp[i+1] == NULL) ) {
390 statusline_msg("Press any key to continue...");
398 statusline_msg(char *msg)
401 statusline_addstr(msg);
404 fprintf(stderr, "statusline_msg(\"%s\")\n", msg);
410 statusline_addstr(char *str)
412 mvwaddstr(bottom, 1, 0, str);
418 * function statusline_getnstr
422 * if n >= 0 str is a pointer which points a place where to store
423 * the string, else str is ingnored
425 * the maximum length of the string
426 * If n < 0 function will allocate needed space for the string.
427 * Value 0 is not allowed for n.
429 * if this value is nonzero the fileselector is enabled
432 * If n < 0 a pointer to a newly allocated string is returned.
433 * If n > 0 a nonzero value is returned if user has typed a valid
434 * string. If not NULL value is returned. Never really use the
435 * _pointer_ if n > 0.
440 statusline_getnstr(char *str, int n, int use_filesel)
448 buf = wenter_string(bottom, n,
449 (use_filesel ? ESTR_USE_FILESEL:0) | ESTR_DONT_WRAP);
457 strncpy(str, buf, n);
471 mvwhline(bottom, 0, 0, ACS_HLINE, COLS);
472 mvwhline(bottom, 2, 0, ACS_HLINE, COLS);
480 ask_filename(char *prompt, int flags)
486 statusline_addstr(prompt);
487 buf = statusline_getnstr(NULL, -1, flags);
504 parse_command_line(int argc, char **argv)
508 for( i = 1; i < argc; i++ ) {
509 if( !strcmp(argv[i], "--help") ) {
513 if( !strcmp(argv[i], "--mutt-query") )
514 mutt_query(argv[i + 1]);
516 if( !strcmp(argv[i], "--datafile") ) {
518 if (argv[i+1][0] != '/') {
519 char *cwd = my_getcwd();
520 datafile = strconcat(cwd, "/", argv[i+1], NULL);
523 datafile = strdup(argv[i+1]);
531 if( !strcmp(argv[i], "--convert") ) {
532 if( argc < 5 || argc > 6 ) {
533 fprintf(stderr, "incorrect number of argumets to make conversion\n");
534 fprintf(stderr, "try %s --help\n", argv[0]);
538 convert(argv[i+1], argv[i+2],
539 argv[i+3], argv[i+4]);
541 convert(argv[i+1], argv[i+2], argv[i+3], "-");
543 printf("option %s not recognized\n", argv[i]);
544 printf("try %s --help\n", argv[0]);
554 puts (PACKAGE " v " VERSION "\n");
555 puts (" --help show usage");
556 puts (" --datafile <filename> use an alternative addressbook file");
557 puts (" --mutt-query <string> make a query for mutt");
558 puts (" --convert <inputformat> <inputfile> "
559 "<outputformat> <outputfile>");
561 puts ("available formats for --convert option:");
564 puts ("\nWarning: this version compiled with DEBUG flag ON");
568 extern list_item *database;
572 muttq_print_item(int item)
574 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
577 split_emailstr(item, emails);
579 for(i = 0; i < (options_get_int("mutt_return_all_emails") ?
580 MAX_EMAILS : 1) ; i++)
582 printf("%s\t%s\t%s\n", emails[i],
583 database[item][NAME],
584 database[item][NOTES] == NULL ? " " :
585 database[item][NOTES]
590 mutt_query_name(char *str)
595 for(i = 0, j = 0 ; i < items; i++) {
596 tmp = strdup(database[i][NAME]);
597 if( strstr( strupper(tmp), strupper(str) ) != NULL ) {
610 mutt_query_email(char *str)
613 char *tmp, emails[MAX_EMAILS][MAX_EMAIL_LEN];
615 for(i = 0, j = 0; i < items; i++) {
616 split_emailstr(i, emails);
617 for(k = 0; k < MAX_EMAILS; k++) {
619 tmp = strdup( emails[k] );
620 if( strstr( strupper(tmp), strupper(str) ) != NULL ) {
624 if( options_get_int("mutt_return_all_emails") ) {
629 printf("%s\t%s\n", emails[k],
641 mutt_query(char *str)
647 if( str == NULL || !strcasecmp(str, "all") ) {
648 printf("All items\n");
649 for(i = 0; i < items; i++)
652 if( !mutt_query_name(str) && !mutt_query_email(str) ) {
653 printf("Not found\n");
667 if( load_database(datafile) ) {
668 printf("Cannot open database\n");
675 quit_mutt_query(int status)
688 char email[MAX_EMAIL_LEN];
690 char *tmp = options_get_str("mutt_command");
695 cmd = strconcat(tmp, " '", NULL );
697 for(i=0; i < items; i++) {
698 if( ! selected[i] && i != curitem )
700 get_first_email(email, i);
701 tmp = mkstr("%s \"%s\"", cmd, database[i][NAME]);
703 if( *database[i][EMAIL] ) {
704 cmd = mkstr("%s <%s>", tmp, email);
708 cmd = strconcat(tmp, " ", NULL);
712 tmp = mkstr("%s%c", cmd, '\'');
716 fprintf(stderr, "cmd: %s\n", cmd);
732 if( database[curitem][URL] )
733 cmd = mkstr("%s '%s'",
734 options_get_str("www_command"),
735 safe_str(database[curitem][URL]));
747 abook_malloc(size_t size)
751 if ( (ptr = malloc(size)) == NULL ) {
752 if(top) /* determinate if init_abook has been called */
754 perror("malloc() failed");
762 abook_realloc(void *ptr, size_t size)
764 ptr = realloc(ptr, size);
770 if(top) /* determinate if init_abook has been called */
772 perror("realloc() failed");
780 abook_fopen (const char *path, const char *mode)
784 if( ! strchr(mode, 'r') )
785 return fopen(path, mode);
787 if ( (stat(path, &s)) == -1 )
790 return S_ISREG(s.st_mode) ? fopen(path, mode) : NULL;
800 should_resize = TRUE;
808 struct winsize winsz;
810 ioctl (0, TIOCGWINSZ, &winsz);
812 if(winsz.ws_col >= MIN_COLS && winsz.ws_row >= MIN_LINES) {
813 fprintf(stderr, "Warning: COLS=%d, LINES=%d\n", winsz.ws_col, winsz.ws_row);
817 if(winsz.ws_col >= MIN_COLS && winsz.ws_row >= MIN_LINES) {
818 #ifdef HAVE_RESIZETERM
819 resizeterm(winsz.ws_row, winsz.ws_col);
822 LINES = winsz.ws_row;
826 should_resize = FALSE;
827 close_list(); /* we need to recreate windows */
833 #endif /* TIOCGWINSZ */
835 #endif /* SIGWINCH */
839 convert(char *srcformat, char *srcfile, char *dstformat, char *dstfile)
843 if( !srcformat || !srcfile || !dstformat || !dstfile ) {
844 fprintf(stderr, "too few argumets to make conversion\n");
845 fprintf(stderr, "try --help\n");
851 if( !strcmp(srcformat, dstformat) ) {
852 printf( "input and output formats are the same\n"
860 switch( import(srcformat, srcfile) ) {
862 printf("input format %s not supported\n", srcformat);
865 printf("cannot read file %s\n", srcfile);
870 switch( export(dstformat, dstfile) ) {
872 printf("output format %s not supported\n",
877 printf("cannot write file %s\n", dstfile);
893 filename = ask_filename("File to open: ", 1);
900 if( options_get_int("autosave") )
903 statusline_addstr("Save current database (y/N)");
914 load_database(filename);
917 statusline_msg("Sorry, that specified file appears not to be a valid abook addressbook");
918 load_database(datafile);
921 datafile = strdup(filename);