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

Last change on this file since 3154 was 3154, checked in by bruno, 6 years ago
  • Remove the introduction of LogProgress? in ListKernelModulePaths? which should stay quiet
  • Remove a remaining support of max-noof-media in confidure.in now gone.
  • Fix #640 by cleaning up fully the managemnt of tmpdir and scratchdir (one function for the creation, one point of removal at end, intermediate removal if needed, clean naming conventions, unify mkdtemp usage, remove sensibly_set_tmpdir_and_scratchdir function). Consequence is that default dir for scratchdir if nothing else specified is /tmp using CLI and the largest partition using the GUI.
  • Fix a bug introduced in process_the_s_switch with intermediate variables which weren't initialized correctly.
  • Property svn:keywords set to Id
File size: 48.9 KB
Line 
1/* newt-specific.c
2   $Id: newt-specific.c 3154 2013-06-22 22:34:33Z 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 3154 2013-06-22 22:34:33Z 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("mondo.tmp");
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.