source: branches/3.0/mondo/src/common/newt-specific.c @ 3141

Last change on this file since 3141 was 3141, checked in by bruno, 6 years ago

r5345@localhost: bruno | 2013-06-13 12:46:54 +0200

  • Solving #702 by adding a -F option which is meant to be used especially when mondoarchive is launched from cron, to avoid going into a loop where mondoarchive asks questions to the admin, where they cannot be answerd, which fills the logs and the underlying file system. With -F mondoarchive will exits at the first interaction request instead.
  • Property svn:keywords set to Id
File size: 48.9 KB
Line 
1/* newt-specific.c
2   $Id: newt-specific.c 3141 2013-06-13 16:05:57Z bruno $
3
4  subroutines which do display-type things
5  and use the newt library to do them
6*/
7
8
9/**
10 * @file
11 * Functions for doing display-type things with the Newt library.
12 */
13
14#define MAX_NEWT_COMMENT_LEN 200
15
16#if __cplusplus
17extern "C" {
18#endif
19
20#include "my-stuff.h"
21#include "mr_mem.h"
22#include "mondostructures.h"
23#include "newt-specific.h"
24#include "libmondo-string-EXT.h"
25#include "libmondo-files-EXT.h"
26#include "libmondo-devices-EXT.h"
27#include "libmondo-tools-EXT.h"
28#include "libmondo-fork-EXT.h"
29#include "libmondo-gui-EXT.h"
30#include "lib-common-externs.h"
31
32extern char *MONDO_LOGFILE;
33
34extern struct s_bkpinfo *bkpinfo;
35
36/*@unused@*/
37//static char cvsid[] = "$Id: newt-specific.c 3141 2013-06-13 16:05:57Z bruno $";
38
39    extern pid_t g_mastermind_pid;
40    /*
41    extern char *g_tmpfs_mountpt;
42    */
43    extern char *g_boot_mountpt;
44    extern char *ps_options;
45    extern char *ps_proc_id;
46
47    extern void set_signals(int);
48
49/**
50 * @addtogroup globalGroup
51 * @{
52 */
53/**
54 * Whether we are currently in a nested call of fatal_error().
55 */
56    bool g_exiting = FALSE;
57
58// Decide whether we should continue to ask questions or exit (cron use case)
59extern bool g_fail_immediately;
60
61/**
62 * Padding below the Newt components, to overcome bugs in Newt.
63 */
64    char g_haharrrrr[500];
65
66
67    newtComponent g_timeline = NULL,    ///< The line of the progress form that shows the time elapsed/remaining
68        g_percentline = NULL,   ///< The line of the progress form that shows the percent completed/remaining
69        g_scale = NULL,         ///< The progress bar component in the progress form
70        g_progressForm = NULL,  ///< The progress form component itself
71        g_blurb1 = NULL,        ///< The component for line 1 of the blurb in the progress form
72        g_blurb2 = NULL,        ///< The component for line 2 of the blurb in the progress form
73        g_blurb3 = NULL,        ///< The component for line 3 (updated continuously) of the blurb in the progress form
74        g_label = NULL;         ///< ????? @bug ?????
75
76/**
77 * Padding above the Newt components, to overcome bugs in Newt.
78 */
79    char g_jim_lad_yarr[500];
80    char **err_log_lines = NULL,    ///< The list of log lines to show on the screen.
81        g_blurb_str_1[MAX_NEWT_COMMENT_LEN] = "",   ///< The string for line 1 of the blurb in the progress form
82        g_blurb_str_2[MAX_NEWT_COMMENT_LEN] = "",   ///< The string for line 2 of the blurb in the progress form
83        g_blurb_str_3[MAX_NEWT_COMMENT_LEN] = "";   ///< The string for line 3 (updated continuously) of the blurb in the progress form
84    newtComponent g_isoform_main = NULL,    ///< The evalcall form component itself
85        g_isoform_header = NULL,    ///< The component for the evalcall form title
86        g_isoform_scale = NULL, ///< The progress bar component in the evalcall form
87        g_isoform_timeline = NULL,  ///< The line of the evalcall form that shows the time elapsed/remaining
88        g_isoform_pcline = NULL;    ///< The line of the evalcall form that shows the percent completed/remaining
89    long g_isoform_starttime;   ///< The time (in seconds since the epoch) that the evalcall form was opened.
90    int g_isoform_old_progress = -1;    ///< The most recent progress update of the evalcall form (percent).
91    char g_isoform_header_str[MAX_STR_LEN] = "                                                                                                               "; ///< The string for the evalcall form title.
92    int g_mysterious_dot_counter;   ///< The counter for the twirling baton (/ | \\ - ...) on percentage less than 3
93    int g_noof_log_lines = 6;   ///< The number of lines to show in the log at the bottom of the screen.
94    int g_noof_rows = 25;       ///< The number of rows on the screen.
95
96    int g_currentY = 3;         ///< The row to write background progress messages to. Incremented each time a message is written.
97    extern int g_current_media_number;
98    pid_t g_main_pid = 0;       ///< The PID of the main Mondo process.
99    long g_maximum_progress = 999;  ///< The maximum amount of progress (100%) for the currently opened progress form.
100    long g_current_progress = -999; ///< The current amount of progress (filelist #, etc.) for the currently opened progress form.
101    long g_start_time = 0;      ///< The time (in seconds since the epoch) that the progress form was opened.
102    bool g_text_mode = TRUE;    ///< If FALSE, use a newt interface; if TRUE, use an ugly (but more compatible) dumb terminal interface.
103    char g_xmondo_stdin[MAX_NEWT_COMMENT_LEN],  ///< ... @bug Unneeded w/current XMondo.
104     g_xmondo_stdout[MAX_NEWT_COMMENT_LEN]; ///< .... @bug Unneeded w/current XMondo.
105    bool g_called_by_xmondo = FALSE;    ///< @bug Unneeded w/current XMondo.
106    char *g_selfmounted_isodir; ///< Holds the NETFS mountpoint if mounted via mondoarchive.
107
108/* @} - end of globalGroup */
109
110//int g_fd_in=-1, g_fd_out=-1;
111
112    void popup_and_OK(char *);
113
114
115/**
116 * @addtogroup guiGroup
117 * @{
118 */
119/**
120 * Ask the user a yes/no question.
121 * @param prompt The question to ask the user.
122 * @return TRUE for yes; FALSE for no.
123 */
124     bool ask_me_yes_or_no(char *prompt) {
125
126        /*@ buffers ********************************************************** */
127        int i;
128        char *p;
129
130        assert_string_is_neither_NULL_nor_zerolength(prompt);
131
132        if (g_fail_immediately) {
133            // We consider the user aborted by using the -F option
134            log_msg(3, "Exiting at first interaction request due to -F");
135            finish(1);
136        }
137        if (g_text_mode) {
138
139            char *tmp;
140            tmp = malloc(MAX_NEWT_COMMENT_LEN);
141
142            while (1) {
143                paranoid_system("sync");
144                printf
145                    ("---promptdialogYN---1--- %s\n---promptdialogYN---Q--- [yes] [no] ---\n--> ",
146                     prompt);
147                p= fgets(tmp, MAX_NEWT_COMMENT_LEN, stdin);
148                if (!p) {
149                    //FIXME
150                }
151                if (tmp[strlen(tmp) - 1] == '\n')
152                    tmp[strlen(tmp) - 1] = '\0';
153
154                i = (int) strlen(tmp);
155                if (i > 0 && tmp[i - 1] < 32) {
156                    tmp[i - 1] = '\0';
157                }
158                if (strstr("yesYES", tmp)) {
159                    paranoid_free(tmp);
160                    return (TRUE);
161                } else if (strstr("NOno", tmp)) {
162                    paranoid_free(tmp);
163                    return (FALSE);
164                } else {
165                    paranoid_system("sync");
166                    printf
167                        ("Please enter either YES or NO (or yes or no, or y or n, or...)\n");
168                }
169            }
170        } else {
171            return (popup_with_buttons(prompt, "Yes", "No"));
172        }
173    }
174
175
176/**
177 * Give the user the opportunity to continue the current operation (OK)
178 * or cancel it (Cancel).
179 * @param prompt The string to be displayed.
180 * @return TRUE for OK, FALSE for Cancel.
181 */
182    bool ask_me_OK_or_cancel(char *prompt) {
183
184        /*@ buffer *********************************************************** */
185        char *tmp;
186        char *p;
187        int i;
188
189        assert_string_is_neither_NULL_nor_zerolength(prompt);
190        if (g_fail_immediately) {
191            // We consider the user aborted by using the -F option
192            log_msg(3, "Exiting at first interaction request due to -F");
193            finish(1);
194        }
195        tmp = malloc(MAX_NEWT_COMMENT_LEN);
196        if (g_text_mode) {
197            paranoid_system("sync");
198            printf
199                ("---promptdialogOKC---1--- %s\n---promptdialogOKC---Q--- [OK] [Cancel] ---\n--> ",
200                 prompt);
201            p = fgets(tmp, MAX_NEWT_COMMENT_LEN, stdin);
202            if (!p) {
203                // FIXME
204            }
205            if (tmp[strlen(tmp) - 1] == '\n')
206                tmp[strlen(tmp) - 1] = '\0';
207
208            i = (int) strlen(tmp);
209            if (i > 0 && tmp[i - 1] < 32) {
210                tmp[i - 1] = '\0';
211            }
212            if (strstr("okOKOkYESyes", tmp)) {
213                paranoid_free(tmp);
214                return (TRUE);
215            } else {
216                paranoid_free(tmp);
217                return (FALSE);
218            }
219        } else {
220            paranoid_free(tmp);
221            return (popup_with_buttons(prompt, " Okay ", "Cancel"));
222        }
223    }
224
225
226
227/**
228 * Close the currently opened evalcall form.
229 */
230    void
231     close_evalcall_form(void) {
232        if (g_text_mode) {
233            return;
234        }
235        if (g_isoform_main == NULL) {
236            return;
237        }
238        update_evalcall_form(100);
239        usleep(500000);
240        if (g_text_mode) {
241            log_msg(2, "Closing evalcall form");
242            return;
243        }
244        newtPopHelpLine();
245        newtFormDestroy(g_isoform_main);
246        newtPopWindow();
247
248        /* Reset globals */
249        g_isoform_main = NULL;
250        g_isoform_old_progress = -1;
251        g_isoform_header = NULL;
252        g_isoform_scale = NULL;
253        g_isoform_timeline = NULL;
254        g_isoform_pcline = NULL;
255}
256
257/**
258 * Close the currently opened progress form.
259 */
260    void
261     close_progress_form() {
262        if (g_text_mode) {
263            return;
264        }
265        if (g_current_progress == -999) {
266            log_msg(2,
267                    "Trying to close the progress form when it ain't open!");
268            return;
269        }
270        g_current_progress = g_maximum_progress;
271        update_progress_form("Complete");
272        sleep(1);
273        if (g_text_mode) {
274            log_msg(2, "Closing progress form");
275            return;
276        }
277        newtPopHelpLine();
278        newtFormDestroy(g_progressForm);
279        newtPopWindow();
280
281        /* Reset globals */
282        g_progressForm = NULL;
283        g_current_progress = -999;
284        g_timeline = NULL;
285        g_percentline = NULL;
286        g_scale = NULL;
287
288    }
289
290/**
291 * Kill any process containing the string @p str surrounded by spaces in its commandline.
292 */
293void kill_anything_like_this(char *str) {
294
295char *tmp = NULL;
296char *tmp1 = NULL;
297
298    mr_asprintf(&tmp,"ps %s | grep \" %s \" | grep -v \"grep\" | awk '{print %s;}'", ps_options, str , ps_proc_id);
299    run_program_and_log_output(tmp, TRUE);
300    if (strlen(tmp) > 0) {
301        mr_asprintf(&tmp1,"kill `%s`", tmp);
302        run_program_and_log_output(tmp1, TRUE);
303        paranoid_free(tmp1);
304    }
305    paranoid_free(tmp);
306}
307
308
309/**
310 * Exit Mondo with a fatal error.
311 * @param error_string The error message to present to the user before exiting.
312 * @note This function never returns.
313 */
314    void
315     fatal_error(char *error_string) {
316        /*@ buffers ***************************************************** */
317        char fatalstr[MAX_NEWT_COMMENT_LEN] =
318            "-------FATAL ERROR---------";
319        char *tmp;
320        char *command;
321        static bool already_exiting = FALSE;
322
323        /*@ end vars **************************************************** */
324
325        malloc_string(command);
326        tmp = malloc(MAX_NEWT_COMMENT_LEN);
327        set_signals(FALSE);     // link to external func
328        g_exiting = TRUE;
329        log_msg(1, "Fatal error received - '%s'", error_string);
330        printf("Fatal error... %s\n", error_string);
331        if (getpid() == g_mastermind_pid) {
332            log_msg(2, "mastermind %d is exiting", (int) getpid());
333            kill(g_main_pid, SIGTERM);
334            paranoid_free(tmp);
335            finish(1);
336        }
337
338        if (getpid() != g_main_pid) {
339            if (g_mastermind_pid != 0 && getpid() != g_mastermind_pid) {
340                log_msg(2, "non-m/m %d is exiting", (int) getpid());
341                kill(g_main_pid, SIGTERM);
342                paranoid_free(tmp);
343                finish(1);
344            }
345        }
346
347        log_msg(3, "OK, I think I'm the main PID.");
348        if (already_exiting) {
349            log_msg(3, "...I'm already exiting. Give me time, Julian!");
350            paranoid_free(tmp);
351            finish(1);
352        }
353
354        already_exiting = TRUE;
355        log_msg(2, "I'm going to do some cleaning up now.");
356        paranoid_system("killall mindi 2> /dev/null");
357        kill_anything_like_this("/mondo/do-not");
358        kill_anything_like_this("tmp.mondo");
359        kill_anything_like_this("ntfsclone");
360        sync();
361        /*
362        sprintf(tmp, "umount %s", g_tmpfs_mountpt);
363        for (i = 0; i < 10 && run_program_and_log_output(tmp, 5); i++) {
364            log_msg(2, "Waiting for child processes to terminate");
365            sleep(1);
366            run_program_and_log_output(tmp, 5);
367        }
368        */
369
370        if (chdir("/")) {
371            // FIXME
372        }
373        if (g_selfmounted_isodir) {
374            sprintf(command, "umount -d %s", g_selfmounted_isodir);
375            run_program_and_log_output(command, 5);
376            sprintf(command, "rmdir %s", g_selfmounted_isodir);
377            run_program_and_log_output(command, 5);
378        }
379
380        if (!g_text_mode) {
381            log_msg(0, fatalstr);
382            log_msg(0, error_string);
383            //      popup_and_OK (error_string);
384            newtFinished();
385        }
386
387        printf("---FATALERROR--- %s\n", error_string);
388        printf
389                ("If you require technical support, please contact the mailing list.\n");
390        printf("See http://www.mondorescue.org for details.\n");
391        printf
392                ("The list's members can help you, if you attach that file to your e-mail.\n");
393        printf("Log file: %s\n", MONDO_LOGFILE);
394        printf("Mondo has aborted.\n");
395        if (!g_main_pid) {
396            log_msg(3, "FYI - g_main_pid is blank");
397        }
398        paranoid_free(tmp);
399        paranoid_free(command);
400        finish(254);
401    }
402
403/* Free memory allocated for newt */
404void free_newt_stuff() {
405
406int i;
407
408for (i = 0; i < g_noof_log_lines; i++) {
409    mr_free(err_log_lines[i]);
410}
411mr_free(err_log_lines);
412}
413
414
415
416/**
417 * Exit Mondo normally.
418 * @param signal The exit code (0 indicates a successful backup; 1 for Mondo means the
419 * user aborted; 254 means a fatal error occured).
420 * @note This function never returns.
421 */
422    void
423     finish(int signal) {
424        char *command = NULL;
425
426        /*  if (signal==0) { popup_and_OK("Please press <enter> to quit."); } */
427
428        /* newtPopHelpLine(); */
429
430        /*  Before removing dir, make sure we're out of them */
431        if (chdir("/tmp")) {
432            // FIXME
433        }
434        run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
435        if (g_selfmounted_isodir) {
436            mr_asprintf(&command, "umount -d %s", g_selfmounted_isodir);
437            run_program_and_log_output(command, 1);
438            paranoid_free(command);
439            mr_asprintf(&command, "rmdir %s", g_selfmounted_isodir);
440            run_program_and_log_output(command, 1);
441            paranoid_free(command);
442        }
443        if (!g_text_mode) {
444            if (does_file_exist("/THIS-IS-A-RAMDISK")) {
445                log_msg(1, "Calling newtFinished()");
446                newtFinished();
447            } else {
448                log_msg(1, "Calling newtSuspend()");
449                newtSuspend();
450            }
451        }
452        printf("Execution run ended; result=%d\n", signal);
453        printf("Type 'less %s' to see the output log\n", MONDO_LOGFILE);
454        if (bkpinfo->tmpdir) {
455            log_msg(8,"tempdir is %s",bkpinfo->tmpdir);
456            if (strstr(bkpinfo->tmpdir ,"mondo.tmp.") != NULL) {
457                log_msg(8,"erasing tempdir %s",bkpinfo->tmpdir);
458                mr_asprintf(&command, "rm -Rf %s", bkpinfo->tmpdir);
459                paranoid_system(command);
460                mr_free(command);
461            }
462        }
463        if (bkpinfo->scratchdir) {
464            log_msg(8,"scratchdir is %s", bkpinfo->scratchdir);
465            if (strstr(bkpinfo->scratchdir ,"mondo.scratch.") != NULL) {
466                log_msg(8,"erasing scratchdir %s",bkpinfo->scratchdir);
467                mr_asprintf(&command, "rm -Rf %s", bkpinfo->scratchdir);
468                paranoid_system(command);
469                mr_free(command);
470            }
471        }
472        /* Free all allocated strings in bkpinfo */
473        mr_free(bkpinfo->netfs_user);
474        mr_free(bkpinfo->netfs_proto);
475        mr_free(bkpinfo->exclude_devs);
476        mr_free(bkpinfo->exclude_paths);
477        mr_free(bkpinfo->subdir);
478
479        /* Then free the structure */
480        paranoid_free(bkpinfo);
481        free_libmondo_global_strings();
482        free_newt_stuff();
483        exit(signal);
484    }
485
486
487
488
489
490/**
491 * Log the last @p g_noof_log_lines lines of @p filename that match @p
492 * grep_for_me to the screen.
493 * @param filename The file to give the end of.
494 * @param grep_for_me If not "", then only give lines in @p filename that match this regular expression.
495 */
496    void
497     log_file_end_to_screen(char *filename, char *grep_for_me) {
498
499        /*@ buffers ********************************************************** */
500        char *command = NULL;
501        char *tmp = NULL;
502        char *p = NULL;
503
504        /*@ pointers ********************************************************* */
505        FILE *fin;
506
507        /*@ int ************************************************************** */
508        int i = 0;
509
510        assert_string_is_neither_NULL_nor_zerolength(filename);
511        assert(grep_for_me != NULL);
512
513        if (!does_file_exist(filename)) {
514            return;
515        }
516        if (grep_for_me[0] != '\0') {
517            mr_asprintf(&command, "grep '%s' %s | tail -n%d",
518                    grep_for_me, filename, g_noof_log_lines);
519        } else {
520            mr_asprintf(&command, "tail -n%d %s", g_noof_log_lines,
521                    filename);
522        }
523        fin = popen(command, "r");
524        if (!fin) {
525            log_OS_error(command);
526        } else {
527            for (i = 0; i < g_noof_log_lines; i++) {
528                for (err_log_lines[i][0] = '\0';
529                     strlen(err_log_lines[i]) < 2 && !feof(fin);) {
530                    p = fgets(err_log_lines[i], MAX_NEWT_COMMENT_LEN, fin);
531                    if (!p) {
532                        // FIXME
533                    }
534                    /* Commented to make valgrind happy and avoid crash
535                    strip_spaces(err_log_lines[i]);
536                    */
537                    if (!strncmp(err_log_lines[i], "root:", 5)) {
538                        mr_asprintf(&tmp, "%s", err_log_lines[i] + 6);
539                        strncpy(err_log_lines[i], tmp, (size_t)MAX_NEWT_COMMENT_LEN);
540                        mr_free(tmp);
541                    }
542                    if (feof(fin)) {
543                        break;
544                    }
545                }
546            }
547            paranoid_pclose(fin);
548        }
549        mr_free(command);
550        refresh_log_screen();
551    }
552
553
554/**
555 * Log a message to the screen.
556 * @param fmt A printf-style format string to write. The following parameters are its arguments.
557 * @note The message is also written to the logfile.
558 */
559    void
560     log_to_screen(const char *fmt, ...) {
561
562        /*@ int ************************************************************** */
563        int i = 0;
564        int j = 0;
565        va_list args;
566
567        /*@ buffers ********************************************************** */
568        char *output;
569
570        malloc_string(output);
571
572        va_start(args, fmt);
573        vsnprintf(output, MAX_STR_LEN-1, fmt, args);
574        log_msg(0, output);
575        output[80] = '\0';
576        va_end(args);
577        i = (int) strlen(output);
578        if (i > 0 && output[i - 1] < 32) {
579            output[i - 1] = '\0';
580        }
581
582        if (err_log_lines) {
583            for (i = 1; i < g_noof_log_lines; i++) {
584                strcpy(err_log_lines[i - 1],
585                       "                                                                                ");
586                strcpy(err_log_lines[i - 1], err_log_lines[i]);
587            }
588        }
589        while (strlen(output) > 0 && output[strlen(output) - 1] < 32) {
590            output[strlen(output) - 1] = '\0';
591        }
592        for (j = 0; j < (int) strlen(output); j++) {
593            if (output[j] < 32) {
594                output[j] = ' ';
595            }
596        }
597        if (err_log_lines)
598            strcpy(err_log_lines[g_noof_log_lines - 1], output);
599        if (g_text_mode) {
600            printf("%s\n", output);
601        } else {
602            refresh_log_screen();
603        }
604        paranoid_free(output);
605    }
606
607
608
609
610/**
611 * Write a string to the root window at (@p x, @p y) and also to the logfile.
612 * @param y The row to write the string to.
613 * @param x The column to write the string to.
614 * @param output The string to write.
615 */
616    void
617     mvaddstr_and_log_it(int y, int x, char *output) {
618        assert_string_is_neither_NULL_nor_zerolength(output);
619        log_msg(0, output);
620        if (g_text_mode) {
621            printf("%s\n", output);
622        } else {
623            newtDrawRootText(x, y, output);
624            newtRefresh();
625        }
626    }
627
628
629
630
631/**
632 * Open an evalcall form with title @p ttl.
633 * @param ttl The title to use for the evalcall form.
634 */
635    void
636     open_evalcall_form(char *ttl) {
637
638        /*@ buffers ********************************************************* */
639        char *title;
640        char *tmp;
641
642        /*@ initialize ****************************************************** */
643        g_isoform_old_progress = -1;
644        g_mysterious_dot_counter = 0;
645        malloc_string(title);
646        malloc_string(tmp);
647
648        assert(ttl != NULL);
649        strcpy(title, ttl);
650        strcpy(g_isoform_header_str, title);
651//  center_string (title, 80);
652        if (g_text_mode) {
653            log_msg(0, title);
654        } else {
655            strcpy(tmp, title);
656            center_string(tmp, 80);
657            newtPushHelpLine(tmp);
658        }
659        center_string(g_isoform_header_str, 36);
660        g_isoform_starttime = get_time();
661        if (g_text_mode) {
662            log_msg(0, g_isoform_header_str);
663        } else {
664            g_isoform_header = newtLabel(1, 1, g_isoform_header_str);
665            g_isoform_scale = newtScale(3, 3, 34, 100);
666            //      newtOpenWindow (20, 6, 40, 7, title);      // "Please Wait");
667            newtCenteredWindow(40, 7, title);
668            g_isoform_main = newtForm(NULL, NULL, 0);
669            g_isoform_timeline = newtLabel(1, 5, "                    ");
670            g_isoform_pcline = newtLabel(1, 6, "                  ");
671            newtFormAddComponents(g_isoform_main, g_isoform_timeline,
672                                  g_isoform_pcline, g_isoform_header,
673                                  g_isoform_scale, NULL);
674            newtDrawForm(g_isoform_main);
675            newtRefresh();
676        }
677        update_evalcall_form(0);
678        paranoid_free(tmp);
679        paranoid_free(title);
680    }
681
682
683
684/**
685 * Open a progress form with title @p title.
686 * @param title The title to use for the progress form (will be put in the title bar on Newt).
687 * @param b1 The first line of the blurb; generally static.
688 * @param b2 The second line of the blurb; generally static.
689 * @param b3 The third line of the blurb; generally dynamic (it is passed
690 * to update_evalcall_form() every time).
691 * @param max_val The maximum amount of progress (number of filesets, etc.)
692 */
693    void
694     open_progress_form(char *title, char *b1, char *b2, char *b3,
695                        long max_val) {
696
697        /*@ buffers ********************************************************* */
698        char *b1c;
699        char *blurb1;
700        char *blurb2;
701        char *blurb3;
702
703        /*@ initialize ****************************************************** */
704        g_mysterious_dot_counter = 0;
705
706        malloc_string(b1c);
707        malloc_string(blurb1);
708        malloc_string(blurb2);
709        malloc_string(blurb3);
710
711        assert(title != NULL);
712        assert(b1 != NULL);
713        assert(b2 != NULL);
714        assert(b3 != NULL);
715
716        strcpy(blurb1, b1);
717        strcpy(blurb2, b2);
718        strcpy(blurb3, b3);
719        strcpy(b1c, b1);
720        center_string(b1c, 80);
721        if (max_val <= 0) {
722            max_val = 1;
723        }
724
725        g_start_time = get_time();
726        g_maximum_progress = max_val;
727        g_current_progress = 0;
728        strcpy(g_blurb_str_1, blurb1);
729        strcpy(g_blurb_str_2, blurb3);
730        strcpy(g_blurb_str_3, blurb2);
731        if (g_text_mode) {
732            log_msg(0, blurb1);
733            log_msg(0, blurb2);
734            log_msg(0, blurb3);
735        } else {
736            g_blurb1 = newtLabel(2, 1, blurb1);
737            g_blurb2 = newtLabel(2, 2, blurb3);
738            g_blurb3 = newtLabel(2, 4, blurb2);
739            //      newtOpenWindow (10, 4, 60, 11, title);
740            newtCenteredWindow(60, 11, title);
741            g_scale = newtScale(3, 6, 54, g_maximum_progress);
742            g_progressForm = newtForm(NULL, NULL, 0);
743            g_percentline = newtLabel(10, 9, "                       ");
744            g_timeline = newtLabel(10, 8, "                    ");
745            newtFormAddComponents(g_progressForm, g_percentline,
746                                  g_timeline, g_scale, g_blurb1, g_blurb3,
747                                  g_blurb2, NULL);
748            newtPushHelpLine(b1c);
749            newtDrawForm(g_progressForm);
750            newtRefresh();
751        }
752        update_progress_form_full(blurb1, blurb2, blurb3);
753        paranoid_free(b1c);
754        paranoid_free(blurb1);
755        paranoid_free(blurb2);
756        paranoid_free(blurb3);
757    }
758
759/**
760 * Give a message to the user in the form of a dialog box (under Newt).
761 * @param prompt The message.
762 */
763    void
764     popup_and_OK(char *prompt) {
765        char ch;
766
767        assert_string_is_neither_NULL_nor_zerolength(prompt);
768
769        log_msg(0, prompt);
770        if (g_text_mode) {
771            printf
772                ("---promptpopup---1--- %s\n---promptpopup---Q--- [OK] ---\n--> ",
773                 prompt);
774            while (((ch = getchar()) != '\n') && (ch != EOF));
775        } else {
776            (void) popup_with_buttons(prompt, " OK ", "");
777        }
778    }
779
780/**
781 * Ask the user to enter a value.
782 * @param title The title of the dialog box.
783 * @param b The blurb (e.g. what you want the user to enter).
784 * @param output The string to put the user's answer in.
785 * @param maxsize The size in bytes allocated to @p output.
786 * @return TRUE if the user pressed OK, FALSE if they pressed Cancel.
787 */
788    bool popup_and_get_string(char *title, char *b, char *output,
789                              int maxsize) {
790
791        /*@ newt ************************************************************ */
792        newtComponent myForm;
793        newtComponent b_1;
794        newtComponent b_2;
795        newtComponent b_res;
796        newtComponent text;
797        newtComponent type_here;
798
799        /*@ pointers ********************************************************* */
800        char *entry_value;
801
802        /*@ buffers ********************************************************** */
803        char *blurb;
804        char *p;
805        char *original_contents;
806
807        blurb = malloc(MAX_NEWT_COMMENT_LEN);
808        original_contents = malloc(MAX_NEWT_COMMENT_LEN);
809        assert_string_is_neither_NULL_nor_zerolength(title);
810        assert(b != NULL);
811        assert(output != NULL);
812
813        if (g_text_mode) {
814            printf
815                ("---promptstring---1--- %s\n---promptstring---2--- %s\n---promptstring---Q---\n-->  ",
816                 title, b);
817            p = fgets(output, maxsize, stdin);
818            if (!p) {
819                // FIXME
820            }
821            if (output[strlen(output) - 1] == '\n')
822                output[strlen(output) - 1] = '\0';
823            paranoid_free(blurb);
824            paranoid_free(original_contents);
825            return (TRUE);
826        }
827        strcpy(blurb, b);
828        text = newtTextboxReflowed(2, 1, blurb, 48, 5, 5, 0);
829        strcpy(original_contents, output);
830        output[0] = '\0';
831        type_here =
832            newtEntry(2, newtTextboxGetNumLines(text) + 2,
833                      original_contents, 50,
834#ifdef __cplusplus
835                      0, NEWT_FLAG_RETURNEXIT
836#else
837                      (void *) &entry_value, NEWT_FLAG_RETURNEXIT
838#endif
839            );
840        b_1 = newtButton(6, newtTextboxGetNumLines(text) + 4, "  OK  ");
841        b_2 = newtButton(18, newtTextboxGetNumLines(text) + 4, "Cancel");
842        //  newtOpenWindow (8, 5, 54, newtTextboxGetNumLines (text) + 9, title);
843        newtCenteredWindow(54, newtTextboxGetNumLines(text) + 9, title);
844        myForm = newtForm(NULL, NULL, 0);
845        newtFormAddComponents(myForm, text, type_here, b_1, b_2, NULL);
846        center_string(blurb, 80);
847        newtPushHelpLine(blurb);
848        b_res = newtRunForm(myForm);
849        strcpy(output, entry_value);
850        newtPopHelpLine();
851        newtFormDestroy(myForm);
852        newtPopWindow();
853        if (b_res == b_2) {
854            strcpy(output, original_contents);
855            paranoid_free(blurb);
856            paranoid_free(original_contents);
857            return (FALSE);
858        } else {
859            paranoid_free(blurb);
860            paranoid_free(original_contents);
861            return (TRUE);
862        }
863    }
864
865
866/**
867 * Pop up a dialog box with user-defined buttons.
868 * @param p The text to put in the dialog box.
869 * @param button1 The label on the first button.
870 * @param button2 The label on the second button, or "" if you only want one button.
871 * @return TRUE if @p button1 was pushed, FALSE otherwise.
872 */
873    bool popup_with_buttons(char *p, char *button1, char *button2) {
874
875        /*@ buffers *********************************************************** */
876        char *prompt;
877        char *q;
878
879        /*@ newt ************************************************************** */
880        newtComponent myForm;
881        newtComponent b_1;
882        newtComponent b_2;
883        newtComponent b_res;
884        newtComponent text;
885
886        assert_string_is_neither_NULL_nor_zerolength(p);
887        assert(button1 != NULL);
888        assert(button2 != NULL);
889        prompt = malloc(MAX_NEWT_COMMENT_LEN);
890        if (g_text_mode) {
891            if (strlen(button2) == 0) {
892                printf("%s (%s) --> ", p, button1);
893            } else {
894                printf("%s (%s or %s) --> ", p, button1, button2);
895            }
896            for (prompt[0] = '\0';
897                 strcmp(prompt, button1) && (strlen(button2) == 0
898                                          || strcmp(prompt, button2));) {
899                printf("--> ");
900                q = fgets(prompt, MAX_NEWT_COMMENT_LEN, stdin);
901                if (!q) {
902                    // FIXME
903                }
904            }
905            if (!strcmp(prompt, button1)) {
906                paranoid_free(prompt);
907                return (TRUE);
908            } else {
909                paranoid_free(prompt);
910                return (FALSE);
911            }
912        }
913
914        strncpy(prompt, p, MAX_NEWT_COMMENT_LEN - 1);
915        prompt[MAX_NEWT_COMMENT_LEN - 1] = '\0';
916        text = newtTextboxReflowed(1, 1, prompt, 40, 5, 5, 0);
917        b_1 =
918            newtButton(20 -
919                       ((button2[0] !=
920                         '\0') ? strlen(button1) +
921                        2 : strlen(button1) / 2),
922                       newtTextboxGetNumLines(text) + 3, button1);
923        if (button2[0] != '\0') {
924            b_2 =
925                newtButton(24, newtTextboxGetNumLines(text) + 3, button2);
926        } else {
927            b_2 = NULL;
928        }
929        //  newtOpenWindow (25, 5, 46, newtTextboxGetNumLines (text) + 7, "Alert");
930        newtCenteredWindow(46, newtTextboxGetNumLines(text) + 7, "Alert");
931        myForm = newtForm(NULL, NULL, 0);
932        newtFormAddComponents(myForm, text, b_1, b_2, NULL);
933        center_string(prompt, 80);
934        newtPushHelpLine(prompt);
935        b_res = newtRunForm(myForm);
936        newtPopHelpLine();
937        newtFormDestroy(myForm);
938        newtPopWindow();
939        if (b_res == b_1) {
940            paranoid_free(prompt);
941            return (TRUE);
942        } else {
943            paranoid_free(prompt);
944            return (FALSE);
945        }
946    }
947
948
949
950
951/**
952 * Synchronize the log messages stored in @p err_log_lines with those shown
953 * on the screen.
954 */
955    void
956     refresh_log_screen() {
957
958        /*@ int *********************************************************** */
959        int i = 0;
960
961
962        if (g_text_mode || !err_log_lines) {
963            return;
964        }
965        for (i = g_noof_log_lines - 1; i >= 0; i--) {
966            newtDrawRootText(0, i + g_noof_rows - 1 - g_noof_log_lines,
967                             "                                                                                ");
968        }
969        newtRefresh();
970        for (i = g_noof_log_lines - 1; i >= 0; i--) {
971            err_log_lines[i][79] = '\0';
972            newtDrawRootText(0, i + g_noof_rows - 1 - g_noof_log_lines,
973                             err_log_lines[i]);
974        }
975        newtRefresh();
976    }
977
978
979/**
980 * Set up the Newt graphical environment. If @p g_text_mode is TRUE, then
981 * only allocate some memory.
982 */
983    void
984     setup_newt_stuff() {
985
986        /*@ int *********************************************************** */
987        int i = 0;
988        int cols;
989
990        if (!g_text_mode) {
991            newtInit();
992            newtCls();
993            newtPushHelpLine
994                ("Welcome to Mondo Rescue, by Dev Team and the Internet. All rights reversed.");
995            /*  newtDrawRootText(28,0,"Welcome to Mondo Rescue"); */
996            newtDrawRootText(18, 0, WELCOME_STRING);
997            newtRefresh();
998            newtGetScreenSize(&cols, &g_noof_rows);
999            g_noof_log_lines = (g_noof_rows / 5) + 1;
1000        }
1001
1002        err_log_lines =
1003            (char **) malloc(sizeof(char *) * g_noof_log_lines);
1004        if (!err_log_lines) {
1005            fatal_error("Out of memory");
1006        }
1007
1008        for (i = 0; i < g_noof_log_lines; i++) {
1009            err_log_lines[i] = (char *) malloc(MAX_NEWT_COMMENT_LEN);
1010            if (!err_log_lines[i]) {
1011                fatal_error("Out of memory");
1012            }
1013        }
1014
1015        for (i = 0; i < g_noof_log_lines; i++) {
1016            err_log_lines[i][0] = '\0';
1017        }
1018    }
1019
1020
1021/**
1022 * Update the evalcall form to show (<tt>num</tt>/<tt>denom</tt>)*100 %.
1023 * @param num The numerator of the ratio.
1024 * @param denom The denomenator of the ratio.
1025 */
1026    void
1027     update_evalcall_form_ratio(int num, int denom) {
1028
1029        /*@ long ************************************************************ */
1030        long current_time = 0;
1031        long time_taken = 0;
1032        long time_total_est = 0;
1033        long time_remaining = 0;
1034
1035        /*@ buffers ********************************************************** */
1036        char *timeline_str;
1037        char *pcline_str = NULL;
1038        char *taskprogress = NULL;
1039
1040        /*@ int ************************************************************** */
1041        int percentage = 0;
1042        int i = 0;
1043        int j = 0;
1044
1045        malloc_string(timeline_str);
1046        timeline_str[0] = '\0';
1047//  log_it("update_eval_call_form called");
1048        if (num * 100 < denom) {
1049            percentage = 1;
1050        } else {
1051            percentage = (num * 100 + denom / 2) / denom;
1052        }
1053
1054        current_time = get_time();
1055        time_taken = current_time - g_isoform_starttime;
1056        if (num) {
1057            time_total_est = time_taken * denom / num;
1058            time_remaining = time_total_est - time_taken;
1059        } else {
1060            time_remaining = 0;
1061        }
1062        if (!g_text_mode) {
1063            if (g_isoform_header) {
1064                newtLabelSetText(g_isoform_header, g_isoform_header_str);
1065            }
1066        }
1067        g_mysterious_dot_counter = (g_mysterious_dot_counter + 1) % 27;
1068        if ((percentage < 3 && g_isoform_old_progress < 3)
1069            || percentage > g_isoform_old_progress) {
1070            g_isoform_old_progress = percentage;
1071            sprintf(timeline_str,
1072                    "%2ld:%02ld taken            %2ld:%02ld remaining",
1073                    (long) time_taken / 60, (long) time_taken % 60, (long) time_remaining / 60,
1074                    (long) time_remaining % 60);
1075            if (percentage < 3) {
1076                mr_asprintf(&pcline_str, " Working");
1077                for (j = 0; j < g_mysterious_dot_counter; j++) {
1078                    mr_strcat(pcline_str, ".");
1079                }
1080                for (; j < 27; j++) {
1081                    mr_strcat(pcline_str, " ");
1082                }
1083                mr_strcat(pcline_str, " %c", special_dot_char(g_mysterious_dot_counter));
1084            } else {
1085                mr_asprintf(&pcline_str, " %3d%% done              %3d%% to go",
1086                        percentage, 100 - percentage);
1087            }
1088            if (g_text_mode) {
1089                mr_asprintf(&taskprogress, "TASK:  [");
1090                for (i = 0; i < percentage; i += 5) {
1091                    mr_strcat(taskprogress, "*");
1092                }
1093                for (; i < 100; i += 5) {
1094                    mr_strcat(taskprogress, ".");
1095                }
1096                if (percentage >= 3) {
1097                    mr_strcat(taskprogress, "] %3d%% done; %2ld:%02ld to go", percentage,
1098                            (long) time_remaining / 60, (long) time_remaining % 60);
1099                    printf("---evalcall---1--- %s\n",
1100                           g_isoform_header_str);
1101                    printf("---evalcall---2--- %s\n", taskprogress);
1102                    printf("---evalcall---E---\n");
1103                }
1104                paranoid_free(taskprogress);
1105            } else {
1106                newtScaleSet(g_isoform_scale,
1107                             (unsigned long long) percentage);
1108                if (g_isoform_pcline) {
1109                    newtLabelSetText(g_isoform_pcline, pcline_str);
1110                }
1111                if ((percentage >= 3) && (g_isoform_timeline)) {
1112                    newtLabelSetText(g_isoform_timeline, timeline_str);
1113                }
1114            }
1115            paranoid_free(pcline_str);
1116        }
1117        if (!g_text_mode) {
1118//      log_it("refreshing");
1119            newtDrawForm(g_isoform_main);
1120            newtRefresh();
1121        }
1122        paranoid_free(timeline_str);
1123    }
1124
1125
1126
1127/**
1128 * Update the evalcall form to show @p curr %.
1129 * @param curr The current amount of progress (percentage) in the evalcall form.
1130 */
1131    void
1132     update_evalcall_form(int curr) {
1133        update_evalcall_form_ratio(curr, 100);
1134    }
1135
1136
1137
1138/**
1139 * Update the progress form to show @p blurb3 and the current value of
1140 * @p g_maximum_progress.
1141 * @param blurb3 The new third line of the blurb; use @p g_blurb_str_2 (no, that's not a typo) to keep it the same.
1142 */
1143    void
1144     update_progress_form(char *blurb3) {
1145        /*  log_it("update_progress_form --- called"); */
1146        if (g_current_progress == -999) {
1147            /* log_it("You're trying to update progress form when it ain't open. Aww, that's OK. I'll let it go. It's a bit naughty but it's a nonfatal error. No prob, Bob."); */
1148            return;
1149        }
1150        strcpy(g_blurb_str_2, blurb3);
1151        update_progress_form_full(g_blurb_str_1, g_blurb_str_2,
1152                                  g_blurb_str_3);
1153    }
1154
1155
1156/**
1157 * Update the progress form's complete blurb and show @p g_current_progress.
1158 * @param blurb1 The first line of the blurb. Use @p g_blurb_str_1 to keep it unchanged.
1159 * @param blurb2 The second line of the blurb. Use @p g_blurb_str_3 (no, that's not a typo) to keep it the same.
1160 * @param blurb3 The third line of the blurb. Use @p g_blurb_str_2 (no, that's not a typo either) to keep it the same.
1161 */
1162    void
1163     update_progress_form_full(char *blurb1, char *blurb2, char *blurb3) {
1164        /*@ long ***************************************************** */
1165        long current_time = 0L;
1166        long time_taken = 0L;
1167        long time_remaining = 0L;
1168        long time_total_est = 0L;
1169
1170        /*@ int ******************************************************* */
1171        int percentage = 0;
1172        int i = 0;
1173
1174        /*@ buffers *************************************************** */
1175        char *percentline_str;
1176        char *timeline_str;
1177        char *taskprogress = NULL;
1178        char *tmp;
1179
1180//  log_msg(1, "'%s' '%s' '%s'", blurb1, blurb2, blurb3);
1181        percentline_str = malloc(MAX_NEWT_COMMENT_LEN);
1182        timeline_str = malloc(MAX_NEWT_COMMENT_LEN);
1183        malloc_string(tmp);
1184        if (!g_text_mode) {
1185            assert(blurb1 != NULL);
1186            assert(blurb2 != NULL);
1187            assert(blurb3 != NULL);
1188            assert(g_timeline != NULL);
1189        }
1190
1191        percentline_str[0] = '\0';
1192
1193        current_time = get_time();
1194        time_taken = current_time - g_start_time;
1195        if (g_maximum_progress == 0) {
1196            percentage = 0;
1197        } else {
1198            if (g_current_progress > g_maximum_progress) {
1199                sprintf(tmp,
1200                        "update_progress_form_full(%s,%s,%s) --- g_current_progress=%ld; g_maximum_progress=%ld",
1201                        blurb1, blurb2, blurb3, g_current_progress,
1202                        g_maximum_progress);
1203                log_msg(0, tmp);
1204                g_current_progress = g_maximum_progress;
1205            }
1206            percentage =
1207                (int) ((g_current_progress * 100L) / g_maximum_progress);
1208        }
1209        if (percentage < 1) {
1210            percentage = 1;
1211        }
1212        if (percentage > 100) {
1213            percentage = 100;
1214        }
1215        if (g_current_progress) {
1216            time_total_est =
1217                time_taken * (long) g_maximum_progress /
1218                (long) (g_current_progress);
1219            time_remaining = time_total_est - time_taken;
1220        } else {
1221            time_remaining = 0L;
1222        }
1223        g_mysterious_dot_counter = (g_mysterious_dot_counter + 1) % 27;
1224        sprintf(timeline_str,
1225                "%2ld:%02ld taken               %2ld:%02ld remaining  ",
1226                (long) time_taken / 60, time_taken % 60, time_remaining / 60,
1227                time_remaining % 60);
1228        sprintf(percentline_str, " %3d%% done                 %3d%% to go",
1229                percentage, 100 - percentage);
1230
1231        if (g_text_mode) {
1232            printf("---progress-form---1--- %s\n", blurb1);
1233            printf("---progress-form---2--- %s\n", blurb2);
1234            printf("---progress-form---3--- %s\n", blurb3);
1235            printf("---progress-form---E---\n");
1236            mr_asprintf(&taskprogress, "TASK:  [");
1237            for (i = 0; i < percentage; i += 5) {
1238                mr_strcat(taskprogress, "*");
1239            }
1240            for (; i < 100; i += 5) {
1241                mr_strcat(taskprogress, ".");
1242            }
1243            if (percentage > 100) {
1244                log_msg(2, "percentage = %d", percentage);
1245            }
1246            mr_strcat(taskprogress, "] %3d%% done; %2ld:%02ld to go", percentage,
1247                            (long) time_remaining / 60, (long) time_remaining % 60);
1248            printf("---progress-form---4--- %s\n", taskprogress);
1249            paranoid_free(taskprogress);
1250        } else {
1251            center_string(blurb1, 54);
1252            center_string(blurb2, 54);
1253            center_string(blurb3, 54);
1254            if (g_blurb1) {
1255                newtLabelSetText(g_blurb1, blurb1);
1256            }
1257            if (g_blurb2) {
1258                newtLabelSetText(g_blurb2, blurb3);
1259            }
1260            if (g_blurb3) {
1261                newtLabelSetText(g_blurb3, blurb2);
1262            }
1263            newtScaleSet(g_scale, (unsigned long long) g_current_progress);
1264            if ((percentage >= 2) && (g_timeline)) {
1265                newtLabelSetText(g_timeline, timeline_str);
1266            }
1267            if (g_percentline) {
1268                newtLabelSetText(g_percentline, percentline_str);
1269            }
1270            newtDrawForm(g_progressForm);
1271            newtRefresh();
1272        }
1273        paranoid_free(percentline_str);
1274        paranoid_free(timeline_str);
1275        paranoid_free(tmp);
1276    }
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291/**
1292 * Ask the user which backup media type they would like to use.
1293 * The choices are @p none (exit to shell), @c cdr, @c cdrw, @c dvd,
1294 * @c tape, @c cdstream, @c udev (only when @p g_text_mode is TRUE), @c netfs,
1295 * and @c iso.
1296 * @param restoring TRUE if we're restoring, FALSE if we're backing up.
1297 * @return The backup type chosen, or @c none if the user chose "Exit to shell".
1298 */
1299    t_bkptype which_backup_media_type(bool restoring) {
1300
1301        /*@ char ************************************************************ */
1302        t_bkptype output;
1303
1304
1305        /*@ newt ************************************************************ */
1306        char *title_sz;
1307        char *minimsg_sz;
1308        static t_bkptype possible_bkptypes[] =
1309            { none, cdr, cdrw, dvd, tape, cdstream, udev, netfs, iso };
1310        static char *possible_responses[] =
1311            { "none", "cdr", "cdrw", "dvd", "tape", "cdstream", "udev",
1312"netfs", "iso", NULL };
1313        char *outstr;
1314        char *p;
1315        t_bkptype backup_type;
1316        int i;
1317
1318        newtComponent b1;
1319        newtComponent b2;
1320        newtComponent b3;
1321        newtComponent b4;
1322        newtComponent b5;
1323        newtComponent b6;
1324        newtComponent b7;
1325        newtComponent b8;
1326        newtComponent b_res;
1327        newtComponent myForm;
1328
1329        title_sz = malloc(MAX_NEWT_COMMENT_LEN);
1330        minimsg_sz = malloc(MAX_NEWT_COMMENT_LEN);
1331        outstr = malloc(MAX_NEWT_COMMENT_LEN);
1332        if (g_text_mode) {
1333            for (backup_type = none; backup_type == none;) {
1334                printf("Backup type (");
1335                for (i = 0; possible_responses[i]; i++) {
1336                    printf("%c%s", (i == 0) ? '\0' : ' ',
1337                           possible_responses[i]);
1338                }
1339                printf(")\n--> ");
1340                p = fgets(outstr, MAX_NEWT_COMMENT_LEN, stdin);
1341                if (!p) {
1342                    // FIXME
1343                }
1344                strip_spaces(outstr);
1345                for (i = 0; possible_responses[i]; i++) {
1346                    if (!strcmp(possible_responses[i], outstr)) {
1347                        backup_type = possible_bkptypes[i];
1348                    }
1349                }
1350            }
1351            paranoid_free(title_sz);
1352            paranoid_free(minimsg_sz);
1353            paranoid_free(outstr);
1354            return (backup_type);
1355        }
1356        newtDrawRootText(18, 0, WELCOME_STRING);
1357        if (restoring) {
1358            strcpy(title_sz,
1359                   "Please choose the backup media from which you want to read data.");
1360            strcpy(minimsg_sz, "Read from:");
1361        } else {
1362            strcpy(title_sz,
1363                   "Please choose the backup media to which you want to archive data.");
1364            strcpy(minimsg_sz, "Backup to:");
1365        }
1366        newtPushHelpLine(title_sz);
1367        //  newtOpenWindow (23, 3, 34, 17, minimsg_sz);
1368        newtCenteredWindow(34, 17, minimsg_sz);
1369        b1 = newtButton(1, 1, "CD-R disks ");
1370        b2 = newtButton(17, 1, "CD-RW disks");
1371        b3 = newtButton(1, 9, "Tape drive ");
1372        b4 = newtButton(17, 5, "USB Key/Disk");
1373        b5 = newtButton(1, 5, " DVD disks ");
1374        b6 = newtButton(17, 9, " Net mount ");
1375        b7 = newtButton(1, 13, " Hard disk ");
1376        b8 = newtButton(17, 13, "    Exit   ");
1377        myForm = newtForm(NULL, NULL, 0);
1378        newtFormAddComponents(myForm, b1, b5, b3, b7, b2, b4, b6, b8,
1379                              NULL);
1380        b_res = newtRunForm(myForm);
1381        newtFormDestroy(myForm);
1382        newtPopWindow();
1383        if (b_res == b1) {
1384            output = cdr;
1385        } else if (b_res == b2) {
1386            output = cdrw;
1387        } else if (b_res == b3) {
1388            output = tape;
1389        } else if (b_res == b4) {
1390            output = usb;
1391        } else if (b_res == b5) {
1392            output = dvd;
1393        } else if (b_res == b6) {
1394            output = netfs;
1395        } else if (b_res == b7) {
1396            output = iso;
1397        } else {
1398            output = none;
1399        }
1400        newtPopHelpLine();
1401        paranoid_free(title_sz);
1402        paranoid_free(minimsg_sz);
1403        paranoid_free(outstr);
1404        return (output);
1405    }
1406
1407
1408
1409
1410/**
1411 * Ask the user which compression type they would like to use.
1412 * The choices are "bzip2", "gzip", "lzo". NULL for exit
1413 */
1414    char *which_compression_type() {
1415
1416        /*@ char ************************************************************ */
1417        char *output = NULL;
1418
1419
1420        /*@ newt ************************************************************ */
1421
1422        newtComponent b1;
1423        newtComponent b2;
1424        newtComponent b3;
1425        //newtComponent b4;
1426        newtComponent b5;
1427        newtComponent b_res;
1428        newtComponent myForm;
1429
1430        newtDrawRootText(18, 0, WELCOME_STRING);
1431        newtPushHelpLine
1432            ("   Please specify the type of compression that you want.");
1433        newtCenteredWindow(34, 13, "Type of compression?");
1434        b1 = newtButton(4, 1, "bzip2");
1435        b2 = newtButton(18, 1, "gzip");
1436        b3 = newtButton(4, 5, "lzo");
1437        //b4 = newtButton(18, 5, "lzma");
1438        b5 = newtButton(4, 9, "         Exit        ");
1439        myForm = newtForm(NULL, NULL, 0);
1440        newtFormAddComponents(myForm, b1, b3, b2, b5, NULL);
1441        b_res = newtRunForm(myForm);
1442        newtFormDestroy(myForm);
1443        newtPopWindow();
1444        if (b_res == b1) {
1445            mr_asprintf(&output, "%s", "bzip2");
1446        } else if (b_res == b2) {
1447            mr_asprintf(&output, "%s", "gzip");
1448        } else if (b_res == b3) {
1449            mr_asprintf(&output, "%s", "lzo");
1450        //} else if (b_res == b4) {
1451            //mr_asprintf(&output, "%s", "lzma");
1452        }
1453        newtPopHelpLine();
1454        return(output);
1455    }
1456
1457
1458/**
1459 * Ask the user how much compression they would like to use.
1460 * The choices are "None" (0), "Minimum" (1), "Average" (4), and "Maximum" (9).
1461 * @return The compression level (0-9) chosen, or -1 for "Exit".
1462 */
1463    int
1464     which_compression_level() {
1465
1466        /*@ char ************************************************************ */
1467        int output = none;
1468
1469
1470        /*@ newt ************************************************************ */
1471
1472        newtComponent b1;
1473        newtComponent b2;
1474        newtComponent b3;
1475        newtComponent b4;
1476        newtComponent b5;
1477        newtComponent b_res;
1478        newtComponent myForm;
1479
1480        newtDrawRootText(18, 0, WELCOME_STRING);
1481        newtPushHelpLine
1482            ("   Please specify the level of compression that you want.");
1483        //  newtOpenWindow (23, 3, 34, 13, "How much compression?");
1484        newtCenteredWindow(34, 13, "How much compression?");
1485        b1 = newtButton(4, 1, "Maximum (9)");
1486        b2 = newtButton(18, 1, "Average (4)");
1487        b3 = newtButton(4, 5, "Minimum (1)");
1488        b4 = newtButton(18, 5, " None (0) ");
1489        b5 = newtButton(4, 9, "         Exit        ");
1490        myForm = newtForm(NULL, NULL, 0);
1491        newtFormAddComponents(myForm, b1, b3, b2, b4, b5, NULL);
1492        b_res = newtRunForm(myForm);
1493        newtFormDestroy(myForm);
1494        newtPopWindow();
1495        if (b_res == b1) {
1496            output = 9;
1497        } else if (b_res == b2) {
1498            output = 4;
1499        } else if (b_res == b3) {
1500            output = 1;
1501        } else if (b_res == b4) {
1502            output = 0;
1503        } else if (b_res == b5) {
1504            output = -1;
1505        }
1506        newtPopHelpLine();
1507        return (output);
1508    }
1509
1510
1511
1512
1513
1514/**
1515 * Load @p source_file (a list of files) into @p filelist. There can be no more than
1516 * @p ARBITRARY_MAXIMUM entries.
1517 * @param filelist The filelist structure to load @p source_file into.
1518 * @param source_file The file containing a list of filenames to load into @p filelist.
1519 */
1520    int load_filelist_into_array(struct s_filelist *filelist,
1521                                 char *source_file) {
1522        int i;
1523        int j = 0;
1524        bool done;
1525        char *tmp;
1526        char *p;
1527        char *tmp1 = NULL;
1528        FILE *fin, *fout;
1529        struct s_filelist_entry dummy_fle;
1530
1531        assert(filelist != NULL);
1532        assert_string_is_neither_NULL_nor_zerolength(source_file);
1533
1534        log_it("entering");
1535        if (!(fin = fopen(source_file, "r"))) {
1536            log_OS_error(source_file);
1537            log_msg(2, "Can't open %s; therefore, cannot popup list",
1538                    source_file);
1539            return (1);
1540        }
1541
1542        mr_asprintf(&tmp1,"%s/icantfindthesefiles.txt",bkpinfo->tmpdir);
1543        if (!(fout = fopen(tmp1, "a"))) {
1544            log_msg(2, "Can't write to %s", tmp1);
1545            return(1);
1546            }
1547
1548        malloc_string(tmp);
1549        log_msg(2, "Loading %s", source_file);
1550        for (filelist->entries = 0; filelist->entries <= ARBITRARY_MAXIMUM;
1551             filelist->entries++) {
1552          god_i_hate_gotos:
1553            if (feof(fin)) {
1554                break;
1555            }
1556            p = fgets(tmp, MAX_NEWT_COMMENT_LEN, fin);
1557            if (!p) {
1558                // FIXME
1559            }
1560            i = (int) strlen(tmp);
1561            if (i < 2) {
1562                goto god_i_hate_gotos;
1563            }
1564            if (tmp[i - 1] < 32) {
1565                tmp[--i] = '\0';
1566            }
1567            if (i < 2) {
1568                goto god_i_hate_gotos;
1569            }
1570            if (!does_file_exist(tmp) && !feof(fin)) {
1571                j++;
1572                fprintf(fout, "%s\n", tmp);
1573
1574                goto god_i_hate_gotos;
1575            }
1576            filelist->el[filelist->entries].severity =
1577                severity_of_difference(tmp, NULL);
1578            strcpy(filelist->el[filelist->entries].filename, tmp);
1579            if (feof(fin)) {
1580                break;
1581            }
1582        }
1583        paranoid_fclose(fin);
1584        paranoid_fclose(fout);
1585        if (j > 0) {
1586            log_to_screen("%d files listed in %s/changed.files have been deleted since backup was made\nand are referenced in %s", j, bkpinfo->tmpdir,tmp1);
1587        }
1588        paranoid_free(tmp1);
1589        if (filelist->entries >= ARBITRARY_MAXIMUM) {
1590            log_to_screen("Arbitrary limits suck, man!");
1591            paranoid_free(tmp);
1592            return (1);
1593        }
1594        for (done = FALSE; !done;) {
1595            done = TRUE;
1596            for (i = 0; i < filelist->entries - 1; i++) {
1597//          if (strcmp(filelist->el[i].filename, filelist->el[i+1].filename) > 0)
1598                if (filelist->el[i].severity < filelist->el[i + 1].severity
1599                    || (filelist->el[i].severity ==
1600                        filelist->el[i + 1].severity
1601                        && strcmp(filelist->el[i].filename,
1602                                  filelist->el[i + 1].filename) > 0)) {
1603                    memcpy((void *) &dummy_fle,
1604                           (void *) &(filelist->el[i]),
1605                           sizeof(struct s_filelist_entry));
1606                    memcpy((void *) &(filelist->el[i]),
1607                           (void *) &(filelist->el[i + 1]),
1608                           sizeof(struct s_filelist_entry));
1609                    memcpy((void *) &(filelist->el[i + 1]),
1610                           (void *) &dummy_fle,
1611                           sizeof(struct s_filelist_entry));
1612                    log_msg(2, "Swapping %s and %s",
1613                            filelist->el[i].filename,
1614                            filelist->el[i + 1].filename);
1615                    done = FALSE;
1616                }
1617            }
1618        }
1619        paranoid_free(tmp);
1620        log_it("leaving");
1621        return (0);
1622    }
1623
1624
1625
1626/**
1627 * Generate a pretty string based on @p flentry.
1628 * @param flentry The filelist entry to stringify.
1629 * @return The string form of @p flentry.
1630 * @note The returned value points to static storage that will be overwritten with each call.
1631 */
1632    char *filelist_entry_to_string(struct s_filelist_entry *flentry) {
1633        static char comment[100];
1634        char *tmp = NULL;
1635
1636        log_it("entering");
1637        assert(flentry != NULL);
1638        if (flentry->severity == 0) {
1639            mr_asprintf(&tmp, "0   ");
1640        } else if (flentry->severity == 1) {
1641            mr_asprintf(&tmp, "low ");
1642        } else if (flentry->severity == 2) {
1643            mr_asprintf(&tmp, "med ");
1644        } else {
1645            mr_asprintf(&tmp, "high");
1646        }
1647        mr_strcat(tmp, "  ");
1648        mr_strcat(tmp, flentry->filename);
1649        strncpy(comment, tmp, 99);
1650        paranoid_free(tmp);
1651
1652        log_it("leaving");
1653        return (comment);
1654    }
1655
1656
1657
1658
1659
1660/**
1661 * Pop up a list containing the filenames in @p source_file and the severity if they have changed since the
1662 * last backup. There can be no more than @p ARBITRARY_MAXIMUM files in @p source_file.
1663 * @param source_file The file containing a list of changed files.
1664 */
1665    void popup_changelist_from_file(char *source_file) {
1666        char *reason;
1667        newtComponent myForm;
1668        newtComponent bClose;
1669        newtComponent bSelect;
1670        newtComponent b_res;
1671        newtComponent fileListbox;
1672        newtComponent headerMsg;
1673
1674        /*@ ???? ************************************************************ */
1675        void *curr_choice;
1676        void *keylist[ARBITRARY_MAXIMUM];
1677
1678        /*@ int ************************************************************* */
1679        int currline = 0;
1680        int finished = FALSE;
1681
1682        /*@ long ************************************************************ */
1683        long i = 0;
1684        long lng = 0;
1685
1686        /*@ buffers ********************************************************* */
1687        char *tmp;
1688        char *differ_sz;
1689
1690        struct s_filelist *filelist;
1691        malloc_string(reason);
1692        tmp = malloc(5000);
1693        malloc_string(differ_sz);
1694        assert_string_is_neither_NULL_nor_zerolength(source_file);
1695        if (g_text_mode) {
1696            log_msg(2, "Text mode. Therefore, no popup list.");
1697            goto free_to_go;
1698        }
1699        log_msg(2, "Examining file %s", source_file);
1700
1701        lng = count_lines_in_file(source_file);
1702        if (lng < 1) {
1703            log_msg(2, "No lines in file. Therefore, no popup list.");
1704            paranoid_free(reason);
1705            goto free_to_go;
1706        } else if (lng >= ARBITRARY_MAXIMUM) {
1707            log_msg(2, "Too many files differ for me to list.");
1708            goto free_to_go;
1709        }
1710
1711        filelist = (struct s_filelist *) malloc(sizeof(struct s_filelist));
1712        fileListbox =
1713            newtListbox(2, 2, 12, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1714        newtListboxClear(fileListbox);
1715
1716        if (load_filelist_into_array(filelist, source_file)) {
1717            log_msg(2, "Can't open %s; therefore, cannot popup list",
1718                    source_file);
1719            paranoid_free(reason);
1720            return;
1721        }
1722        log_msg(2, "%d files loaded into filelist array",
1723                filelist->entries);
1724        for (i = 0; i < filelist->entries; i++) {
1725            keylist[i] = (void *) i;
1726            newtListboxAppendEntry(fileListbox,
1727                                   filelist_entry_to_string(&
1728                                                            (filelist->
1729                                                             el[i])),
1730                                   keylist[i]);
1731        }
1732        sprintf(differ_sz,
1733                "  %ld files differ. Hit 'Select' to pick a file. Hit 'Close' to quit the list.",
1734                i);
1735        newtPushHelpLine(differ_sz);
1736        bClose = newtCompactButton(10, 15, " Close  ");
1737        bSelect = newtCompactButton(30, 15, " Select ");
1738        sprintf(tmp, "%-10s               %-20s", "Priority", "Filename");
1739        headerMsg = newtLabel(2, 1, tmp);
1740        newtOpenWindow(5, 4, 70, 16, "Non-matching files");
1741        myForm = newtForm(NULL, NULL, 0);
1742        newtFormAddComponents(myForm, headerMsg, fileListbox, bClose,
1743                              bSelect, NULL);
1744        while (!finished) {
1745            b_res = newtRunForm(myForm);
1746            if (b_res == bClose) {
1747                finished = TRUE;
1748            } else {
1749                curr_choice = newtListboxGetCurrent(fileListbox);
1750                for (i = 0;
1751                     i < filelist->entries && keylist[i] != curr_choice;
1752                     i++);
1753                if (i == filelist->entries && filelist->entries > 0) {
1754                    log_to_screen("I don't know what that button does!");
1755                } else {
1756                    currline = i;
1757                    if (filelist->entries > 0) {
1758                        severity_of_difference(filelist->el[currline].
1759                                               filename, reason);
1760                        sprintf(tmp, "%s --- %s",
1761                                filelist->el[currline].filename, reason);
1762                        popup_and_OK(tmp);
1763                    }
1764                }
1765            }
1766        }
1767        newtFormDestroy(myForm);
1768        newtPopWindow();
1769        newtPopHelpLine();
1770      free_to_go:
1771        paranoid_free(reason);
1772        paranoid_free(tmp);
1773        paranoid_free(differ_sz);
1774        return;
1775    }
1776
1777/* @} - end of guiGroup */
1778
1779
1780#if __cplusplus
1781}                               /* extern "C" */
1782#endif
Note: See TracBrowser for help on using the repository browser.