Ticket #1577: Apply mc burn patch.eml

File Apply mc burn patch.eml, 28.8 KB (added by slavazanko, 15 years ago)
Line 
1Delivered-To: slavazanko@gmail.com
2Received: by 10.103.170.9 with SMTP id x9cs102907muo;
3        Tue, 1 Sep 2009 11:00:42 -0700 (PDT)
4Received: by 10.223.3.208 with SMTP id 16mr2997752fao.76.1251828041904;
5        Tue, 01 Sep 2009 11:00:41 -0700 (PDT)
6Return-Path: <andy@dhcppc74>
7Received: from suomicom.fi (mail.suomicom.fi [217.119.36.25])
8        by mx.google.com with ESMTP id 10si9406191fxm.13.2009.09.01.11.00.41;
9        Tue, 01 Sep 2009 11:00:41 -0700 (PDT)
10Received-SPF: neutral (google.com: 217.119.36.25 is neither permitted nor denied by best guess record for domain of andy@dhcppc74) client-ip=217.119.36.25;
11Authentication-Results: mx.google.com; spf=neutral (google.com: 217.119.36.25 is neither permitted nor denied by best guess record for domain of andy@dhcppc74) smtp.mail=andy@dhcppc74
12Received: from exim by suomicom.fi with spam-scanned (Exim 4.69)
13        (envelope-from <andy@dhcppc74>)
14        id 1MiXe8-00068r-Vc
15        for slavazanko@gmail.com; Tue, 01 Sep 2009 21:00:32 +0300
16X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on mail.suomicom.fi
17X-Spam-Level:
18X-Spam-Status: No, score=0.3 required=5.5 tests=ALL_TRUSTED,AWL,TVD_RCVD_IP
19        autolearn=disabled version=3.2.5
20Received: from 79-134-110-209.cust.suomicom.fi ([79.134.110.209] helo=dhcppc74)
21        by suomicom.fi with esmtps (TLSv1:AES256-SHA:256)
22        (Exim 4.69)
23        (envelope-from <andy@dhcppc74>)
24        id 1MiXe8-00068l-NK; Tue, 01 Sep 2009 20:59:56 +0300
25Received: from dhcppc74 (localhost.localdomain [127.0.0.1])
26        by dhcppc74 (8.14.3/8.14.3) with ESMTP id n81HwnR7015076;
27        Tue, 1 Sep 2009 20:59:31 +0300
28Received: (from andy@localhost)
29        by dhcppc74 (8.14.3/8.14.3/Submit) id n81Ht4ec014403;
30        Tue, 1 Sep 2009 20:55:04 +0300
31From: Andy Shevchenko <andy.shevchenko@gmail.com>
32To: slavazanko@gmail.com
33Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
34Subject: [PATCH] MCBurn: Apply mc burn patch
35Date: Tue,  1 Sep 2009 20:53:58 +0300
36Message-Id: <1251827638-14313-1-git-send-email-andy.shevchenko@gmail.com>
37X-Mailer: git-send-email 1.6.0.6
38
39This patch allows to write choosed directories to the CD or DVD.
40
41Originally patch was developed [1] by Bart Friederichs
42<bart@friesoft.nl>.
43
44Modifications are:
45 - apply indentation
46 - remove redudant messages
47 - change defaults to not to write (dummy run) and speed to 16x
48 - update to last master branch (4.7.0-pre2)
49
50[1] http://friesoft.nl/software/mcburn.html
51
52Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
53---
54 src/Makefile.am |    1 +
55 src/main.c      |    4 +
56 src/mcburn.c    |  725 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
57 src/mcburn.h    |   19 ++
58 src/setup.c     |    5 +
59 5 files changed, 754 insertions(+), 0 deletions(-)
60 create mode 100644 src/mcburn.c
61 create mode 100644 src/mcburn.h
62
63diff --git a/src/Makefile.am b/src/Makefile.am
64index 57404f4..0450e73 100644
65--- a/src/Makefile.am
66+++ b/src/Makefile.am
67@@ -62,6 +62,7 @@ SRCS =        achown.c achown.h background.c background.h boxes.c boxes.h     \
68        layout.h learn.c learn.h listmode.c listmode.h history.h        \
69        logging.h logging.c main.c main.h main-widgets.h                \
70        menu.c menu.h mountlist.c mountlist.h                           \
71+       mcburn.h mcburn.c                                               \
72        option.c option.h panel.h panelize.c panelize.h poptalloca.h    \
73        popt.c poptconfig.c popt.h popthelp.c poptint.h poptparse.c     \
74        screen.c setup.c setup.h                                        \
75diff --git a/src/main.c b/src/main.c
76index ca38237..c86cb6b 100644
77--- a/src/main.c
78+++ b/src/main.c
79@@ -99,6 +99,8 @@
80 
81 #include "popt.h"
82 
83+#include "mcburn.h"             /* the CD recording extensions */
84+
85 /* When the modes are active, left_panel, right_panel and tree_panel */
86 /* Point to a proper data structure.  You should check with the functions */
87 /* get_current_type and get_other_type the types of the panels before using */
88@@ -752,6 +754,7 @@ static menu_entry CmdMenu[] = {
89     {' ', N_("&Compare directories  C-x d"), NULL_HOTKEY, compare_dirs_cmd},
90     {' ', N_("e&Xternal panelize    C-x !"), NULL_HOTKEY, external_panelize},
91     {' ', N_("show directory s&Izes"), NULL_HOTKEY, dirsizes_cmd},
92+    {' ', N_("B&urn this dir to CD"), NULL_HOTKEY, do_burn},
93     {' ', "", NULL_HOTKEY, 0},
94     {' ', N_("Command &history      M-h"), NULL_HOTKEY, history_cmd},
95     {' ', N_("di&Rectory hotlist    C-\\"), NULL_HOTKEY, quick_chdir_cmd},
96@@ -778,6 +781,7 @@ static menu_entry CmdMenu[] = {
97 /* Must keep in sync with the constants in menu_cmd */
98 static menu_entry OptMenu[] = {
99     {' ', N_("&Configuration..."), NULL_HOTKEY, configure_box},
100+    {' ', N_("CD B&urning config..."), NULL_HOTKEY, burn_config},
101     {' ', N_("&Layout..."), NULL_HOTKEY, layout_cmd},
102     {' ', N_("c&Onfirmation..."), NULL_HOTKEY, confirm_box},
103     {' ', N_("&Display bits..."), NULL_HOTKEY, display_bits_box},
104diff --git a/src/mcburn.c b/src/mcburn.c
105new file mode 100644
106index 0000000..342e343
107--- /dev/null
108+++ b/src/mcburn.c
109@@ -0,0 +1,725 @@
110+/* mcburn.c
111+ * Function definitions for cdrecord support in Midnight Commander
112+ * Copyright 2001 Bart Friederichs
113+ * Copyright 2007-2009 Andy Shevchenko <andy.shevchenko@gmail.com>
114+ */
115+
116+/*
117+ * TODO for future versions
118+ * - Beautify the burn dialog so that it looks like all dialogs in mc.
119+ * - Build in multi-burner/cdrom support
120+ * - Check for enough drive space for image in $HOME_DIR
121+ */
122+
123+#include <config.h>
124+#include <string.h>
125+#include <stdio.h>
126+/* Needed for the extern declarations of integer parameters */
127+#include <sys/types.h>
128+#include <sys/param.h>
129+#include <sys/stat.h>
130+#ifdef HAVE_UNISTD_H
131+#include <unistd.h>
132+#endif                          /* HAVE_UNISTD_H */
133+
134+#include "global.h"
135+
136+#include "../src/tty/tty.h"
137+#include "../src/tty/color.h"
138+
139+#include "widget.h"
140+#include "setup.h"              /* For save_setup() */
141+
142+#include "mcburn.h"
143+#include "wtools.h"
144+#include "execute.h"
145+
146+#define TOGGLE_VARIABLE        0
147+#define INPUT_VARIABLE 1
148+
149+/* Burner options box coords */
150+#define BX     4
151+#define BY     2
152+
153+/* Filesystem option box coords */
154+#define FY     2
155+
156+/* widget types */
157+#define CHECKBOX       1
158+#define INPUT          2
159+
160+/* option category */
161+#define BURNER         1
162+#define FS             2
163+
164+/* watch it! $HOME_DIR will be prepended to this path */
165+static const char *configfile = "/.mc/mcburn.conf";
166+
167+/* global settings */
168+int interimage = 1;
169+int dummyrun = 1;
170+int joliet = 1;
171+int rockridge = 1;
172+int multi = 1;
173+int speed = 16;
174+int scsi_bus = -1, scsi_id = -1, scsi_lun = -1;
175+char *cdwriter = NULL;
176+
177+static int burner_option_width = 0, fs_option_width = 0;
178+static int FX = 0;
179+static char *burn_options_title, *burner_title, *fs_title;
180+static Dlg_head *burn_conf_dlg;
181+static Dlg_head *burn_dlg;
182+static char *burndir;
183+static char *cdrecord_path;
184+static char *mkisofs_path;
185+static int burner_options, fs_options;  /* amount of burner and fs options */
186+
187+/* one struct with all burner settings */
188+static struct {
189+    char *text;
190+    int *variable;
191+    int type;                   /* CHECKBOX, INPUT */
192+    int category;               /* BURNER, FS */
193+    WCheck *w_check;
194+    WInput *w_input;
195+    char *tk;
196+    char *description;
197+
198+    /* only applicable for the input widget; shoot me for the overhead */
199+    int i_length;
200+} options[] = {
201+    {
202+    N_("make &Intermediate image"), &interimage, CHECKBOX, BURNER,
203+            NULL, NULL, "interimage", "Make intermediate image", 0}, {
204+    N_("&Dummy run"), &dummyrun, CHECKBOX, BURNER, NULL, NULL,
205+            "dummyrun", "Turn the laser off", 0}, {
206+    N_("&Multisession CD"), &multi, CHECKBOX, BURNER, NULL, NULL,
207+            "multi", "Create a multi-session CD", 0}, {
208+    N_("Speed"), &speed, INPUT, BURNER, NULL, NULL, "speed", "Speed", 3}, {
209+    N_("&Joliet extensions"), &joliet, CHECKBOX, FS, NULL, NULL,
210+            "joliet", "Use Joliet extensions", 0}, {
211+    N_("&RockRidge extensions"), &rockridge, CHECKBOX, FS, NULL, NULL,
212+            "rockridge", "Use RockRidge extensions", 0}, {
213+    0, 0, 0, 0}
214+};
215+
216+/* return a string that is a concatenation of s1 and s2 */
217+char *concatstrings(const char *s1, const char *s2)
218+{
219+    char *temp = NULL;
220+    int length = 0;
221+
222+    length = strlen(s1) + strlen(s2) + 1;
223+    temp = malloc(length * sizeof(char));
224+
225+    strcpy(temp, s1);
226+    strcat(temp, s2);
227+
228+    return (temp);
229+}
230+
231+/* check for program and return a pointer to a string containing the full path */
232+char *check_for(char *program)
233+{
234+    char *command;
235+    FILE *output;
236+
237+    char buffer[1024];
238+    char *fullpath;
239+
240+    command = malloc((strlen(program) + 11) * sizeof(char));
241+    strcpy(command, "which ");
242+    strcat(command, program);
243+    strcat(command, " 2>&1");
244+
245+    if (!(output = popen(command, "r"))) {
246+        message(0, "Error ",
247+                "An error occurred checking for program (popen failed)");
248+        return NULL;
249+    }
250+
251+    while (!feof(output))
252+        fgets(buffer, 1024, output);
253+
254+    /* remove newline from buffer */
255+    buffer[strlen(buffer) - 1] = '\0';
256+
257+    /* not starting with '/' means it is not found */
258+    if (buffer[0] != '/')
259+        return NULL;
260+
261+    fullpath = malloc((strlen(buffer) + 1) * sizeof(char));
262+    strncpy(fullpath, buffer, strlen(buffer) + 1);
263+
264+    pclose(output);
265+    return fullpath;
266+}
267+
268+/* this lets the user choose a dir and burn that dir, with the
269+   current options */
270+void do_burn()
271+{
272+    char buffer[1024];
273+
274+    /* make sure cdrecord and mkisofs is available, and get their full path */
275+    if (!(mkisofs_path = check_for("mkisofs"))) {
276+        message(0, " Error ", "Couldn't find mkisofs");
277+        return;
278+    }
279+
280+    if (!(cdrecord_path = check_for("cdrecord"))) {
281+        message(0, " Error ", "Couldn't find cdrecord");
282+        return;
283+    }
284+
285+    if (!strcmp
286+        (current_panel->dir.list[current_panel->selected].fname, "..")) {
287+        message(0, " Error ", "You can't burn the parent-directory");
288+        return;
289+    }
290+
291+    burndir = concat_dir_and_file(current_panel->cwd,
292+                                  current_panel->dir.list[current_panel->
293+                                  selected].fname);
294+
295+    if (!S_ISDIR
296+        (current_panel->dir.list[current_panel->selected].st.st_mode)) {
297+        message(0, " Error ", "You can't burn a single file to CD");
298+        return;
299+    } else {
300+        if (!scan_for_recorder(cdrecord_path)) {
301+            sprintf(buffer, "No CD-Writer found");
302+            message(0, " Error ", buffer);
303+            return;
304+        }
305+
306+        init_burn();            /* initialize the burn dialog */
307+        run_dlg(burn_dlg);      /* run the dialog */
308+        destroy_dlg(burn_dlg);  /* and throw it away after usage */
309+
310+        if (burn_dlg->ret_value == B_ENTER) {
311+            /* here, the actual burning takes place construct a
312+             * (series of) command(s) to execute
313+             */
314+
315+            sprintf(buffer, "echo \"Burning %s to CD ...\"", burndir);
316+            shell_execute(buffer, EXECUTE_INTERNAL);
317+
318+            /*  continue here
319+             *  1. make a mkisofs command
320+             *  2. make a cdrecord command
321+             *  3. pipe them if necessary (!interimage)
322+             *  4. run consecutively if necessary (interimage)
323+             *  NOTE: dummyrun is NOT before writing, its just a
324+             *        dummy run (nice for testing purposes)
325+             */
326+
327+            /* STEP 1: create an image if the user wants to. Put
328+             *         the image in $HOMEDIR it's the user's
329+             *         responsibility to make sure the is enough
330+             *         room (TODO 3) this is where the fs-options
331+             *         come in, using -r for RockRidge and -J for
332+             *         Joliet extensions
333+             */
334+            if (interimage) {
335+                sprintf(buffer, "echo \"Building image...\"");
336+                shell_execute(buffer, EXECUTE_INTERNAL);
337+                strcpy(buffer, mkisofs_path);
338+                if (rockridge)
339+                    strcat(buffer, " -r");
340+                if (joliet)
341+                    strcat(buffer, " -J");
342+                strcat(buffer, " -o ");
343+                strcat(buffer, home_dir);
344+                strcat(buffer, "/mcburn.iso ");
345+                strcat(buffer, burndir);
346+                shell_execute(buffer, EXECUTE_INTERNAL);
347+            }
348+
349+            /* STEP 2: create a cdrecord command, this is where
350+             *         speed, dummy, multi and the scsi_* vars come
351+             *         in also, check for an image or pipe it right
352+             *         into cdrecord
353+             *
354+             * STEP 2b: cdrecord without a pipe (assume the
355+             *          $HOME/mcburn.iso exists (TODO 4))
356+             */
357+            if (interimage) {
358+                sprintf(buffer, "echo \"Burning CD...\"");
359+                shell_execute(buffer, EXECUTE_INTERNAL);
360+                strcpy(buffer, cdrecord_path);
361+                if (dummyrun)
362+                    strcat(buffer, " -dummy");
363+                if (multi)
364+                    strcat(buffer, " -multi");
365+                sprintf(buffer, "%s -v speed=%d", buffer, speed);
366+                sprintf(buffer, "%s dev=%d,%d,%d", buffer, scsi_bus,
367+                        scsi_id, scsi_lun);
368+                sprintf(buffer, "%s -data %s/mcburn.iso", buffer,
369+                        home_dir);
370+            } else {
371+                /* no image present, pipe mkisofs into cdrecord */
372+                /* first get the size of the image to build */
373+                FILE *pipe;
374+                int imagesize;
375+                strcpy(buffer,
376+                       "mkisofs -R -q -print-size private_collection/  2>&1 | sed -e \"s/.* = //\"");
377+                pipe = popen(buffer, "r");
378+                fgets(buffer, 1024, pipe);
379+                imagesize = atoi(buffer);
380+                pclose(pipe);
381+
382+                sprintf(buffer,
383+                        "[ \"0%d\" -ne 0 ] && %s %s %s %s | %s %s %s speed=%d dev=%d,%d,%d -data -",
384+                        imagesize, mkisofs_path, rockridge ? " -r" : "",
385+                        joliet ? " -J" : "", burndir, cdrecord_path,
386+                        dummyrun ? " -dummy" : "", multi ? " -multi" : "",
387+                        speed, scsi_bus, scsi_id, scsi_lun);
388+            }
389+
390+            /* execute the burn command */
391+            shell_execute(buffer, EXECUTE_INTERNAL);
392+        }
393+    }
394+}
395+
396+/* scan for CD recorder
397+   This functions executes 'cdrecord -scanbus' and checks the output for 'CD-ROM'. It gets the first occurrence.
398+   In the future, it should give all available CD-ROMs so that the user can choose from them
399+   Also, the bus, id and lun received from the line can be wrong.
400+
401+   return 1 if a recorder is found, 0 otherwise
402+*/
403+int scan_for_recorder(char *cdrecord_command)
404+{
405+    char *command;
406+    char buffer[1024];
407+    FILE *output;
408+
409+    command = calloc((strlen(cdrecord_command) + 15), sizeof(char));
410+    strncpy(command, cdrecord_command, strlen(cdrecord_command));
411+    strcat(command, " -scanbus 2>&1");
412+
413+    if (!(output = popen(command, "r"))) {
414+        message(0, "Error ",
415+                "An error occurred scanning for writers (popen failed)");
416+        return 0;
417+    }
418+
419+    while (!feof(output)) {
420+        int i = -1;
421+
422+        fgets(buffer, 1024, output);
423+
424+        /* remove newline from buffer */
425+        buffer[strlen(buffer) - 1] = '\0';
426+
427+        for (i = 0; i < strlen(buffer); i++)
428+            if (buffer[i] == '\'')
429+                break;
430+
431+        /* parse all lines from 'cdrecord -scanbus' and select the first CD-ROM */
432+        if (buffer[0] == '\t' && strstr(buffer, "CD-ROM")) {
433+            /* this is a scsi cdrom player in this line */
434+            scsi_bus = buffer[1] - 48;
435+            scsi_id = buffer[3] - 48;
436+            scsi_lun = buffer[5] - 48;
437+
438+            /* free the memory first, before allocating new */
439+            if (cdwriter)
440+                g_free(cdwriter);
441+            cdwriter = calloc(26, sizeof(char));
442+            strncpy(cdwriter, &buffer[i + 1], 8);
443+            strcat(cdwriter, " ");
444+            strncat(cdwriter, &buffer[i + 12], 16);
445+
446+            break;
447+            /* remove this to select _last_ occurence, i should
448+             * make a menu where the user can choose */
449+        }
450+    }
451+
452+    g_free(command);
453+    pclose(output);
454+
455+    /* if the scsi_* vars are still -1, no recorder was found */
456+    if (scsi_lun == -1)
457+        return 0;
458+    else
459+        return 1;
460+}
461+
462+/* the burn dialog box message handler
463+ * the burn dialog could use some better layout
464+ */
465+static cb_ret_t burn_callback(struct Dlg_head *h, dlg_msg_t Msg, int parm)
466+{
467+    int i, line = 4;
468+    char buffer[1025];
469+
470+    switch (Msg) {
471+    case DLG_DRAW:
472+#ifndef HAVE_X
473+        tty_setcolor(COLOR_NORMAL);
474+        dlg_erase(h);
475+        draw_box(h, 0, 0, h->lines, h->cols);
476+
477+        dlg_move(h, 1, 1);
478+        tty_print_string(_("directory:"));
479+
480+        tty_setcolor(COLOR_YELLOW);
481+        dlg_move(h, 1, 11);
482+        tty_print_string(burndir);
483+        tty_setcolor(COLOR_NORMAL);
484+
485+        dlg_move(h, 3, 1);
486+        tty_print_string(_("settings:"));
487+
488+        /* run through all options */
489+        for (i = 0; options[i].tk; i++) {
490+            switch (options[i].type) {
491+            case CHECKBOX:
492+                if (*options[i].variable == 1) {
493+                    dlg_move(h, line, 1);
494+                    tty_print_string(_("- "));
495+                    dlg_move(h, line++, 4);
496+                    tty_print_string(options[i].description);
497+                }
498+                break;
499+            case INPUT:
500+                dlg_move(h, line, 1);
501+                tty_print_string(options[i].description);
502+                dlg_move(h, line++, strlen(options[i].description) + 2);
503+                sprintf(buffer, "%d", *options[i].variable);
504+                tty_print_string(buffer);
505+                break;
506+            default:
507+                break;
508+            }
509+        }
510+#endif
511+        break;
512+    case DLG_END:
513+        break;
514+    default:
515+        break;
516+    }
517+
518+    return 0;
519+}
520+
521+/* this initializes the burn dialog box
522+   there will be no way back after OK'ing this one */
523+void init_burn()
524+{
525+    int i;
526+
527+    int dialog_height = 0, dialog_width = 27;
528+
529+    /* button titles */
530+    char *burn_button = _("&Burn");
531+    char *cancel_button = _("&Cancel");
532+
533+    /* we need the height and width of the dialog
534+       that depends on the settings */
535+    for (i = 0; options[i].tk; i++)
536+        switch (options[i].type) {
537+        case CHECKBOX:
538+            if (*options[i].variable == 1)
539+                /* just print the setting when it is checked */
540+                dialog_height++;
541+            break;
542+        case INPUT:
543+            /* these are always printed */
544+            dialog_height++;
545+            break;
546+        default:
547+            break;
548+        }
549+
550+    dialog_height += 7;
551+
552+    if (strlen(burndir) + 12 > 27)
553+        dialog_width = strlen(burndir) + 12;
554+
555+    burn_dlg =
556+        create_dlg(0, 0, dialog_height, dialog_width, dialog_colors,
557+                   burn_callback, "CD Burn", _("Burn directory to CD"),
558+                   DLG_CENTER);
559+
560+    /* add the Burn and Cancel buttons */
561+    add_widget(burn_dlg,
562+               button_new(dialog_height - 2, 1, B_ENTER, DEFPUSH_BUTTON,
563+                          burn_button, 0));
564+
565+    add_widget(burn_dlg,
566+               button_new(dialog_height - 2, 12, B_CANCEL, NORMAL_BUTTON,
567+                          cancel_button, 0));
568+
569+}
570+
571+/******************************************************************************
572+               MC-Burn options functions
573+*******************************************************************************/
574+
575+/* this shows the burn options dialog */
576+void burn_config()
577+{
578+    int result, i;
579+
580+    init_burn_config();
581+
582+    run_dlg(burn_conf_dlg);
583+
584+    /* they pushed the OK or Save button, set the variables right */
585+    result = burn_conf_dlg->ret_value;
586+
587+    if (result == B_ENTER || result == B_EXIT)
588+        for (i = 0; options[i].tk; i++)
589+            switch (options[i].type) {
590+            case CHECKBOX:
591+                if (options[i].w_check->state & C_CHANGE)
592+                    *options[i].variable = !(*options[i].variable);
593+                break;
594+            case INPUT:
595+                *options[i].variable = atoi(options[i].w_input->buffer);
596+                break;
597+            }
598+
599+    /* If they pressed the save button, save the values to ~/.mc/mcburn.conf */
600+    if (result == B_EXIT) {
601+        save_mcburn_settings();
602+    }
603+
604+    destroy_dlg(burn_conf_dlg);
605+}
606+
607+/* the options dialog box message handler */
608+static cb_ret_t burn_options_callback(struct Dlg_head *h, dlg_msg_t Msg,
609+                                      int parm)
610+{
611+    switch (Msg) {
612+    case DLG_DRAW:
613+#ifndef HAVE_X
614+        tty_setcolor(COLOR_NORMAL);
615+        dlg_erase(h);
616+
617+        /* all around the dialog box box */
618+        draw_box(h, 1, 2, h->lines - 2, h->cols - 4);
619+
620+        /* option boxes */
621+        draw_box(h, BY, BX, burner_options + 2, burner_option_width);
622+        draw_box(h, FY, FX, fs_options + 2, fs_option_width);
623+
624+        /* titles */
625+        dlg_move(h, 1, (h->cols - strlen(burn_options_title)) / 2);
626+        tty_print_string(burn_options_title);
627+        dlg_move(h, BY, BX + 2);
628+        tty_print_string(burner_title);
629+        dlg_move(h, FY, FX + 2);
630+        tty_print_string(fs_title);
631+
632+#endif
633+        break;
634+
635+    case DLG_END:
636+        break;
637+    default:
638+        break;
639+    }
640+    return 0;
641+}
642+
643+/* this initializes the burn options dialog box */
644+void init_burn_config()
645+{
646+    int i = 0;
647+    static int dialog_height = 0, dialog_width = 0;
648+    static int b1, b2, b3;
649+
650+    /* button title */
651+    char *ok_button = _("&Ok");
652+    char *cancel_button = _("&Cancel");
653+    char *save_button = _("&Save");
654+    register int l1;
655+
656+    burner_options = 0;
657+    fs_options = 0;
658+
659+    /* count the amount of burner and fs options */
660+    for (i = 0; options[i].tk; i++)
661+        switch (options[i].category) {
662+        case BURNER:
663+            burner_options++;
664+            break;
665+        case FS:
666+            fs_options++;
667+            break;
668+        }
669+
670+    /* similar code is in options.c */
671+    burn_options_title = _(" CD-Burn options ");
672+    burner_title = _(" Burner options ");
673+    fs_title = _(" Filesystem options ");
674+
675+    /* get the widths for the burner options and the fs options */
676+    burner_option_width = strlen(burner_title) + 1;
677+    fs_option_width = strlen(fs_title) + 1;
678+    for (i = 0; options[i].tk; i++) {
679+        /* make sure the whole inputfield width is accounted for */
680+        if (options[i].type == INPUT)
681+            l1 = options[i].i_length;
682+        else
683+            l1 = 0;
684+
685+        /* calculate longest width of text */
686+        if (options[i].category == BURNER) {
687+            options[i].text = _(options[i].text);
688+            l1 += strlen(options[i].text) + 7;
689+            if (l1 > burner_option_width)
690+                burner_option_width = l1;
691+        }
692+
693+        if (options[i].category == FS) {
694+            options[i].text = _(options[i].text);
695+            l1 += strlen(options[i].text) + 7;
696+            if (l1 > fs_option_width)
697+                fs_option_width = l1;
698+        }
699+
700+    }
701+
702+    l1 = 11 + strlen(ok_button)
703+        + strlen(save_button)
704+        + strlen(cancel_button);
705+
706+    i = (burner_option_width + fs_option_width - l1) / 4;
707+    b1 = 5 + i;
708+    b2 = b1 + strlen(ok_button) + i + 6;
709+    b3 = b2 + strlen(save_button) + i + 4;
710+
711+    dialog_width = burner_option_width + fs_option_width + 7;
712+    FX = FY + burner_option_width + 2;
713+
714+    /* figure out the height for the burn options dialog */
715+    if (burner_options > fs_options)
716+        dialog_height = burner_options + 7;
717+    else
718+        dialog_height = fs_options + 7;
719+
720+    burn_conf_dlg =
721+        create_dlg(0, 0, dialog_height, dialog_width, dialog_colors,
722+                   burn_options_callback, "CD Burn options",
723+                   _("Burner options"), DLG_CENTER);
724+
725+    /* add the OK, Cancel and Save buttons */
726+    add_widget(burn_conf_dlg,
727+               button_new(dialog_height - 3, b1, B_ENTER, DEFPUSH_BUTTON,
728+                          ok_button, 0));
729+
730+    add_widget(burn_conf_dlg,
731+               button_new(dialog_height - 3, b2, B_EXIT, NORMAL_BUTTON,
732+                          save_button, 0));
733+
734+    add_widget(burn_conf_dlg,
735+               button_new(dialog_height - 3, b3, B_CANCEL, NORMAL_BUTTON,
736+                          cancel_button, 0));
737+
738+
739+    /* add the burner options */
740+    for (i = 0; options[i].tk; i++) {
741+        int x = 0, y = 0;
742+        char *defvalue;
743+
744+        /* first find out where the widget should go (burner option or fs option) */
745+        switch (options[i].category) {
746+        case BURNER:
747+            x = BX + 1;
748+            y = BY + 1 + i;
749+            break;
750+        case FS:
751+            x = FX + 1;
752+            y = FY - burner_options + 1 + i;
753+            break;
754+        default:
755+            break;
756+        }
757+
758+        /* then create a new widget, depending on the type
759+         * afterwards, add it to the dialog box                                 */
760+        switch (options[i].type) {
761+        case CHECKBOX:
762+            options[i].w_check = check_new(y, x, *options[i].variable, options[i].text);        /* here, the values are taken from the variables and put in the checkboxes */
763+            add_widget(burn_conf_dlg, options[i].w_check);
764+            break;
765+        case INPUT:
766+            defvalue = malloc((options[i].i_length + 1) * sizeof(char));
767+            snprintf(defvalue, options[i].i_length, "%d",
768+                     *options[i].variable);
769+
770+            add_widget(burn_conf_dlg, label_new(y, x, options[i].text));        /* a label */
771+            options[i].w_input = input_new(y, x + strlen(options[i].text) + 1, 0, options[i].i_length, defvalue, options[i].tk, INPUT_COMPLETE_DEFAULT);        /* and the input widget behind it */
772+            add_widget(burn_conf_dlg, options[i].w_input);
773+            break;
774+        default:
775+            break;
776+        }
777+    }
778+
779+}
780+
781+/******************************************************************************
782+               MC-Burn configfile functions
783+*******************************************************************************/
784+
785+/* this loads the settings from ~/.mc/mcburn.conf */
786+void load_mcburn_settings()
787+{
788+    FILE *mcburn_settings_file;
789+    char *filename;
790+    int i, setting;
791+    char buff[128];
792+
793+    filename = malloc(strlen(home_dir) + strlen(configfile) + 1);
794+    strcpy(filename, home_dir);
795+    strcat(filename, configfile);
796+
797+    if ((mcburn_settings_file = fopen(filename, "r")) != NULL) {
798+        while (!feof(mcburn_settings_file)) {
799+            fscanf(mcburn_settings_file, "%s %d", buff, &setting);
800+
801+            for (i = 0; options[i].tk; i++) {
802+                if (!strcmp(options[i].tk, buff)) {
803+                    *options[i].variable = setting;
804+                }
805+            }
806+        }
807+        fclose(mcburn_settings_file);
808+    }
809+}
810+
811+/* this saves the settings to ~/.mc/mcburn.conf */
812+void save_mcburn_settings()
813+{
814+    FILE *mcburn_settings_file;
815+    int i;
816+    char *filename;
817+
818+    filename = malloc(strlen(home_dir) + strlen(configfile) + 1);
819+    strcpy(filename, home_dir);
820+    strcat(filename, configfile);
821+
822+    if ((mcburn_settings_file = fopen(filename, "w")) == NULL) {
823+        message(0, " Save failed ", filename);
824+    } else {
825+        /* first, print a message not to tamper with the file */
826+        fprintf(mcburn_settings_file,
827+                "# This file is generated by MC-Burn. DO NOT EDIT!\n");
828+        for (i = 0; options[i].tk; i++) {
829+            fprintf(mcburn_settings_file, "%s %d\n", options[i].tk,
830+                    *options[i].variable);
831+        }
832+        fclose(mcburn_settings_file);
833+    }
834+}
835diff --git a/src/mcburn.h b/src/mcburn.h
836new file mode 100644
837index 0000000..6c0c3b1
838--- /dev/null
839+++ b/src/mcburn.h
840@@ -0,0 +1,19 @@
841+/* mcburn.h
842+ * Header file for cdrecord support in Midnight Commander
843+ * Copyright 2001 Bart Friederichs
844+ * Copyright 2007-2009 Andy Shevchenko <andy.shevchenko@gmail.com>
845+ */
846+
847+#ifndef __MCBURN_H
848+#define __MCBURN_H
849+
850+void do_burn();
851+void burn_config();
852+void init_burn_config();        /* initialize burner config dialog */
853+void init_burn();               /* initialize burner dialog */
854+void load_mcburn_settings();
855+void save_mcburn_settings();
856+int scan_for_recorder(char *);
857+char *concatstrings(const char *, const char *);        /* returns a string that is the concatenation of s1 and s2 */
858+
859+#endif
860diff --git a/src/setup.c b/src/setup.c
861index 2da1458..5ede2a7 100644
862--- a/src/setup.c
863+++ b/src/setup.c
864@@ -67,6 +67,7 @@
865 
866 #include "../src/strutil.h"    /* str_isutf8 () */
867 
868+#include "mcburn.h"
869 
870 extern char *find_ignore_dirs;
871 
872@@ -299,6 +300,8 @@ save_layout (void)
873     }
874     mc_config_save_to_file (mc_main_config, profile);
875 
876+    save_mcburn_settings();
877+
878     g_free (profile);
879 }
880 
881@@ -680,6 +683,8 @@ load_setup (void)
882     if ( get_codepage_id( display_codepage ) )
883         utf8_display = str_isutf8 (get_codepage_id( display_codepage ));
884 #endif /* HAVE_CHARSET */
885+
886+    load_mcburn_settings();
887 }
888 
889 #if defined(USE_VFS) && defined (USE_NETCODE)
890--
8911.6.0.6
892