diff --git a/crates/icy_board/src/menu_runner/login.rs b/crates/icy_board/src/menu_runner/login.rs
index 0ff64b0d..8a0454ca 100644
--- a/crates/icy_board/src/menu_runner/login.rs
+++ b/crates/icy_board/src/menu_runner/login.rs
@@ -291,7 +291,8 @@ impl PcbBoardCommand {
                 }
             }
             if settings.ask_xfer_protocol {
-                let protocol = self.state.ask_protocols("N".to_string()).await?;
+                let protocol = self.state.ask_protocols("N").await?;
+                self.state.new_line().await?;
                 if !protocol.is_empty() {
                     new_user.protocol = protocol;
                 } else {
@@ -656,7 +657,7 @@ impl PcbBoardCommand {
         self.state.new_line().await?;
         let date_formats = self.state.get_board().await.languages.date_formats.clone();
 
-        self.state.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        self.state.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         let mut preview = String::new();
         for (i, (disp_fmt, fmt)) in date_formats.iter().enumerate() {
             if fmt == cur_format {
diff --git a/crates/icy_board_engine/src/data/ICBTEXT.toml b/crates/icy_board_engine/src/data/ICBTEXT.toml
index c0a3dce6..4ee33bd1 100644
--- a/crates/icy_board_engine/src/data/ICBTEXT.toml
+++ b/crates/icy_board_engine/src/data/ICBTEXT.toml
@@ -1848,7 +1848,7 @@ style = "White"
 text = "Output File Name"
 style = "Red"
 
-[BatchDownloadTime]
+[_BatchDownloadTime]
 text = "Batch Download Time:~"
 style = "Yellow"
 
diff --git a/crates/icy_board_engine/src/icy_board/icb_config.rs b/crates/icy_board_engine/src/icy_board/icb_config.rs
index 10e49052..884c3f24 100644
--- a/crates/icy_board_engine/src/icy_board/icb_config.rs
+++ b/crates/icy_board_engine/src/icy_board/icb_config.rs
@@ -194,6 +194,43 @@ pub enum IcbColor {
     IcyEngine(Color),
 }
 
+impl IcbColor {
+    pub fn dos_black() -> Self {
+        IcbColor::Dos(0x00)
+    }
+    pub fn dos_blue() -> Self {
+        IcbColor::Dos(0x00)
+    }
+
+    pub fn dos_light_blue() -> Self {
+        IcbColor::Dos(0x09)
+    }
+
+    pub fn dos_light_green() -> Self {
+        IcbColor::Dos(0x0A)
+    }
+
+    pub fn dos_cyan() -> Self {
+        IcbColor::Dos(0x0B)
+    }
+
+    pub fn dos_light_red() -> Self {
+        IcbColor::Dos(0x0C)
+    }
+
+    pub fn dos_magenta() -> Self {
+        IcbColor::Dos(0x0D)
+    }
+
+    pub fn dos_yellow() -> Self {
+        IcbColor::Dos(0x0E)
+    }
+
+    pub fn dos_white() -> Self {
+        IcbColor::Dos(0x0F)
+    }
+}
+
 impl From<u8> for IcbColor {
     fn from(color: u8) -> Self {
         IcbColor::Dos(color)
diff --git a/crates/icy_board_engine/src/icy_board/icb_text.rs b/crates/icy_board_engine/src/icy_board/icb_text.rs
index 08a13624..fc05c834 100644
--- a/crates/icy_board_engine/src/icy_board/icb_text.rs
+++ b/crates/icy_board_engine/src/icy_board/icb_text.rs
@@ -979,7 +979,7 @@ pub enum IceText {
     /// `Output File Name`
     OutputFileName = 479,
     /// `Batch Download Time:~`
-    BatchDownloadTime = 480,
+    _BatchDownloadTime = 480,
     /// `Batch Download Size:~`
     BatchDownloadSize = 481,
     /// `Batch Protocol Type: ~`
@@ -1633,13 +1633,13 @@ impl IcbTextStyle {
     pub fn to_color(&self) -> IcbColor {
         match self {
             IcbTextStyle::Plain => IcbColor::None,
-            IcbTextStyle::Red => IcbColor::Dos(12),
-            IcbTextStyle::Green => IcbColor::Dos(10),
-            IcbTextStyle::Yellow => IcbColor::Dos(14),
-            IcbTextStyle::Blue => IcbColor::Dos(9),
-            IcbTextStyle::Purple => IcbColor::Dos(13),
-            IcbTextStyle::Cyan => IcbColor::Dos(11),
-            IcbTextStyle::White => IcbColor::Dos(15),
+            IcbTextStyle::Red => IcbColor::dos_light_red(),
+            IcbTextStyle::Green => IcbColor::dos_light_green(),
+            IcbTextStyle::Yellow => IcbColor::dos_yellow(),
+            IcbTextStyle::Blue => IcbColor::dos_light_blue(),
+            IcbTextStyle::Purple => IcbColor::dos_magenta(),
+            IcbTextStyle::Cyan => IcbColor::dos_cyan(),
+            IcbTextStyle::White => IcbColor::dos_white(),
         }
     }
 
diff --git a/crates/icy_board_engine/src/icy_board/state/functions.rs b/crates/icy_board_engine/src/icy_board/state/functions.rs
index 75ae486d..5752cc3d 100644
--- a/crates/icy_board_engine/src/icy_board/state/functions.rs
+++ b/crates/icy_board_engine/src/icy_board/state/functions.rs
@@ -46,17 +46,6 @@ pub mod display_flags {
     pub const NOTBLANK: i32 = 0x02000; // same as 'AUTO'
 }
 
-pub mod pcb_colors {
-    use crate::icy_board::icb_config::IcbColor;
-
-    pub const BLUE: IcbColor = IcbColor::Dos(9);
-    pub const GREEN: IcbColor = IcbColor::Dos(10);
-    pub const CYAN: IcbColor = IcbColor::Dos(11);
-    pub const RED: IcbColor = IcbColor::Dos(12);
-    pub const MAGENTA: IcbColor = IcbColor::Dos(13);
-    pub const YELLOW: IcbColor = IcbColor::Dos(14);
-    pub const WHITE: IcbColor = IcbColor::Dos(15);
-}
 const TXT_STOPCHAR: char = '_';
 
 lazy_static::lazy_static! {
@@ -233,7 +222,7 @@ impl IcyBoardState {
         let Ok(content) = fs::read(resolved_name) else {
             if display_error {
                 self.bell().await?;
-                self.set_color(TerminalTarget::Both, pcb_colors::RED).await?;
+                self.set_color(TerminalTarget::Both, IcbColor::dos_light_red()).await?;
                 self.print(TerminalTarget::Both, &format!("\r\n({}) is missing!\r\n\r\n", file_name.as_ref().display()))
                     .await?;
             }
diff --git a/crates/icy_board_engine/src/icy_board/state/menu_runner.rs b/crates/icy_board_engine/src/icy_board/state/menu_runner.rs
index 0cb44340..85f2dad3 100644
--- a/crates/icy_board_engine/src/icy_board/state/menu_runner.rs
+++ b/crates/icy_board_engine/src/icy_board/state/menu_runner.rs
@@ -224,7 +224,7 @@ impl IcyBoardState {
             }
             CommandType::FlagFiles => {
                 // FLAG
-                self.flag_files().await?;
+                self.flag_files_cmd(false).await?;
             }
             CommandType::EnterMessage => {
                 // E
diff --git a/crates/icy_board_engine/src/icy_board/state/mod.rs b/crates/icy_board_engine/src/icy_board/state/mod.rs
index 830d39f5..803cbed5 100644
--- a/crates/icy_board_engine/src/icy_board/state/mod.rs
+++ b/crates/icy_board_engine/src/icy_board/state/mod.rs
@@ -1,5 +1,5 @@
 use std::{
-    collections::{HashMap, HashSet, VecDeque},
+    collections::{HashMap, VecDeque},
     fmt::Alignment,
     fs,
     path::{Path, PathBuf},
@@ -102,35 +102,16 @@ impl Default for DisplayOptions {
 pub struct TransferStatistics {
     pub downloaded_files: usize,
     pub downloaded_bytes: usize,
+    pub downloaded_cps: usize,
+
     pub uploaded_files: usize,
     pub uploaded_bytes: usize,
-
-    pub dl_transfer_time: usize,
-    pub ul_transfer_time: usize,
+    pub uploaded_cps: usize,
 }
 
 impl TransferStatistics {
-    pub fn get_cps_download(&self) -> usize {
-        if self.dl_transfer_time == 0 {
-            return 0;
-        }
-        self.downloaded_bytes / self.dl_transfer_time
-    }
-
-    pub fn get_cps_upload(&self) -> usize {
-        if self.ul_transfer_time == 0 {
-            return 0;
-        }
-        self.uploaded_bytes / self.ul_transfer_time
-    }
-
     pub fn get_cps_both(&self) -> usize {
-        let total_time = self.dl_transfer_time + self.ul_transfer_time;
-        if total_time == 0 {
-            return 0;
-        }
-        // actually correct - it's not the average, but the accumlated csp
-        (self.downloaded_bytes + self.uploaded_bytes) / total_time
+        (self.downloaded_cps + self.uploaded_cps) / 2
     }
 }
 
@@ -205,7 +186,7 @@ pub struct Session {
 
     // The maximum number of files in flagged_files
     pub batch_limit: usize,
-    pub flagged_files: HashSet<PathBuf>,
+    pub flagged_files: Vec<PathBuf>,
 }
 
 impl Session {
@@ -250,7 +231,7 @@ impl Session {
             saved_color: IcbColor::Dos(7),
 
             sysop_name: "SYSOP".to_string(),
-            flagged_files: HashSet::new(),
+            flagged_files: Vec::new(),
             emsi: None,
             paged_sysop: false,
             bytes_remaining: 0,
@@ -1027,7 +1008,7 @@ impl IcyBoardState {
                 return Ok(());
             }
             if ch.source == KeySource::Sysop {
-                self.set_color(TerminalTarget::Both, IcbColor::Dos(10)).await?;
+                self.set_color(TerminalTarget::Both, IcbColor::dos_light_green()).await?;
             } else {
                 self.reset_color(TerminalTarget::Both).await?;
             }
@@ -1377,7 +1358,9 @@ impl IcyBoardState {
             "FIRSTU" => {
                 result = self.session.get_first_name().to_uppercase();
             }
-            "FNUM" => {}
+            "FNUM" => {
+                result = (self.session.flagged_files.len() + 1).to_string();
+            }
             "FREESPACE" => {}
             "GFXMODE" => {
                 result = match self.session.disp_options.grapics_mode {
@@ -1478,7 +1461,7 @@ impl IcyBoardState {
                 return None;
             }
             "PROLTR" | "PRODESC" | "PWXDATE" | "PWXDAYS" | "QOFF" | "QON" | "RATIOBYTES" | "RATIOFILES" => {}
-            "RCPS" => result = self.transfer_statistics.get_cps_upload().to_string(),
+            "RCPS" => result = self.transfer_statistics.uploaded_cps.to_string(),
             "RBYTES" => result = self.transfer_statistics.uploaded_bytes.to_string(),
             "RFILES" => result = self.transfer_statistics.uploaded_files.to_string(),
             "REAL" => {
@@ -1491,7 +1474,7 @@ impl IcyBoardState {
                     result = user.security_level.to_string()
                 }
             }
-            "SCPS" => result = self.transfer_statistics.get_cps_download().to_string(),
+            "SCPS" => result = self.transfer_statistics.downloaded_cps.to_string(),
             "SBYTES" => result = self.transfer_statistics.downloaded_bytes.to_string(),
             "SFILES" => result = self.transfer_statistics.downloaded_files.to_string(),
             "SYSDATE" => {
@@ -1799,7 +1782,7 @@ impl IcyBoardState {
         let pos = self.user_screen.caret.get_position();
         self.set_activity(NodeStatus::NodeMessage).await;
         self.new_line().await?;
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(15)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_white()).await?;
         self.println(TerminalTarget::Both, &"Broadcast:").await?;
         self.println(TerminalTarget::Both, &msg).await?;
         self.bell().await?;
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/login.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/login.rs
index 90a91b01..3ae2279d 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/login.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/login.rs
@@ -279,7 +279,7 @@ impl IcyBoardState {
                 }
             }
             if settings.ask_xfer_protocol {
-                let protocol = self.ask_protocols("N".to_string()).await?;
+                let protocol = self.ask_protocols("N").await?;
                 if !protocol.is_empty() {
                     new_user.protocol = protocol;
                 } else {
@@ -610,7 +610,7 @@ impl IcyBoardState {
         self.new_line().await?;
         let date_formats = self.get_board().await.languages.date_formats.clone();
 
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         let mut preview = String::new();
         for (i, (disp_fmt, fmt)) in date_formats.iter().enumerate() {
             if fmt == cur_format {
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/mods/editor/mod.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/mods/editor/mod.rs
index 2ac8fecb..8ac7014a 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/mods/editor/mod.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/mods/editor/mod.rs
@@ -122,7 +122,7 @@ impl EditState {
                         let line: usize = self.read_line_number(IceText::DeleteLineNumber, state).await?;
                         if line > 0 && (line as usize - 1) < self.msg.len() {
                             self.print_divider(state).await?;
-                            state.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+                            state.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
                             state.print(TerminalTarget::Both, &format!("{}: ", line)).await?;
                             state.reset_color(TerminalTarget::Both).await?;
                             state.println(TerminalTarget::Both, &self.msg[line - 1]).await?;
@@ -194,7 +194,7 @@ impl EditState {
 
         let to_part = format!("{}{}", to_txt, self.to);
         let subj_part = format!("{}{} {}", subj_txt, self.subj, Local::now().format("%H:%M"));
-        state.set_color(TerminalTarget::Both, IcbColor::Dos(14)).await?;
+        state.set_color(TerminalTarget::Both, IcbColor::dos_yellow()).await?;
         state.println(TerminalTarget::Both, &format!("{:<38}{:<38}", to_part, subj_part)).await?;
         self.print_divider(state).await?;
 
@@ -202,7 +202,7 @@ impl EditState {
     }
 
     async fn print_divider(&mut self, state: &mut IcyBoardState) -> Res<()> {
-        state.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        state.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         state.println(TerminalTarget::Both, &str::repeat("-", 79)).await?;
         state.reset_color(TerminalTarget::Both).await?;
         Ok(())
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/mods/filebrowser/more_prompt.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/mods/filebrowser/more_prompt.rs
index a0863dac..0bfeb9a1 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/mods/filebrowser/more_prompt.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/mods/filebrowser/more_prompt.rs
@@ -27,7 +27,7 @@ impl IcyBoardState {
             self.session.push_tokens(&input);
             match self.session.tokens.pop_front().unwrap_or_default().to_ascii_uppercase().as_str() {
                 "F" | "FL" | "FLA" | "FLAG" => {
-                    self.flag_files().await?;
+                    self.flag_files_cmd(false).await?;
                 }
                 "V" | "S" => {
                     self.view_file().await?;
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/mods/fileview/mod.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/mods/fileview/mod.rs
index 70c1bf47..2795956b 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/mods/fileview/mod.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/mods/fileview/mod.rs
@@ -70,7 +70,7 @@ impl IcyBoardState {
                         .await?;
                     self.println(TerminalTarget::Both, "  Length      Date    Time   Name").await?;
                     self.println(TerminalTarget::Both, " ========  ========== ===== ======").await?;
-                    self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+                    self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
                     for info in &file_content {
                         if self.session.disp_options.abort_printout {
                             break;
@@ -90,11 +90,11 @@ impl IcyBoardState {
                         self.println(TerminalTarget::Both, &info.name).await?;
                         len += info.size;
                     }
-                    self.set_color(TerminalTarget::Both, IcbColor::Dos(14)).await?;
+                    self.set_color(TerminalTarget::Both, IcbColor::dos_yellow()).await?;
                     self.set_color(TerminalTarget::Both, colors.file_head.clone()).await?;
                     self.println(TerminalTarget::Both, "---------                   ------").await?;
                     self.set_color(TerminalTarget::Both, colors.file_size).await?;
-                    self.set_color(TerminalTarget::Both, IcbColor::Dos(15)).await?;
+                    self.set_color(TerminalTarget::Both, IcbColor::dos_white()).await?;
                     self.println(
                         TerminalTarget::Both,
                         &format!("{:>9}                   {} files", humanize_bytes_decimal!(len).to_string(), file_content.len()),
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/d_download.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/d_download.rs
index 7a8d6847..980e90fc 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/d_download.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/d_download.rs
@@ -1,5 +1,11 @@
+use std::os::unix::fs::MetadataExt;
 use std::path::PathBuf;
 
+use async_recursion::async_recursion;
+use humanize_bytes::humanize_bytes_decimal;
+
+use crate::icy_board::icb_config::IcbColor;
+use crate::icy_board::state::functions::MASK_NUM;
 use crate::{icy_board::state::IcyBoardState, Res};
 use crate::{
     icy_board::{icb_text::IceText, state::functions::display_flags},
@@ -8,76 +14,240 @@ use crate::{
 
 impl IcyBoardState {
     pub async fn download(&mut self) -> Res<()> {
-        if self.session.flagged_files.is_empty() {
-            self.println(TerminalTarget::Both, "No files flagged for download.").await?;
-            self.new_line().await?;
-            self.press_enter().await?;
-            self.display_current_menu = true;
+        if !self.session.flagged_files.is_empty() {
+            let download_tagged = self
+                .input_field(
+                    IceText::DownloadTagged,
+                    1,
+                    "",
+                    &"",
+                    Some(self.session.yes_char.to_string()),
+                    display_flags::NEWLINE | display_flags::UPCASE | display_flags::LFBEFORE | display_flags::YESNO | display_flags::FIELDLEN,
+                )
+                .await?;
+
+            if download_tagged == self.session.no_char.to_uppercase().to_string() {
+                self.new_line().await?;
+                self.press_enter().await?;
+                self.display_current_menu = true;
+                return Ok(());
+            }
         }
 
-        let download_tagged = self
-            .input_field(
-                IceText::DownloadTagged,
-                1,
-                "",
-                &"",
-                Some(self.session.yes_char.to_string()),
-                display_flags::NEWLINE | display_flags::UPCASE | display_flags::YESNO | display_flags::FIELDLEN,
-            )
-            .await?;
+        self.flag_files_cmd(true).await?;
 
-        if download_tagged == self.session.no_char.to_uppercase().to_string() {
-            self.new_line().await?;
+        if self.session.flagged_files.is_empty() {
             self.press_enter().await?;
             self.display_current_menu = true;
             return Ok(());
         }
 
-        let protocol_str: String = self.session.current_user.as_ref().unwrap().protocol.clone();
+        let mut protocol_str: String = self.session.current_user.as_ref().unwrap().protocol.clone();
         let mut protocol = None;
-        for p in &self.get_board().await.protocols.protocols {
-            if p.is_enabled && p.char_code == protocol_str {
-                protocol = Some(p.send_command.clone());
-                break;
+        let mut p_descr = "None".to_string();
+
+        let mut goodbye_after_dl = false;
+        let mut do_dl = true;
+        loop {
+            for p in &self.get_board().await.protocols.protocols {
+                if p.is_enabled && p.char_code == protocol_str {
+                    p_descr = p.description.clone();
+                    protocol = Some(p.send_command.clone());
+                    break;
+                }
             }
-        }
 
-        if let Some(protocol) = protocol {
-            let mut prot = protocol.create();
-            let files: Vec<PathBuf> = self.session.flagged_files.drain().collect();
-            for f in &files {
-                if !f.exists() {
-                    log::error!("File not found: {:?}", f);
-                    self.session.op_text = f.file_name().unwrap().to_string_lossy().to_string();
-                    self.display_text(IceText::NotFoundOnDisk, display_flags::NEWLINE).await?;
-                    self.new_line().await?;
-                    self.press_enter().await?;
-                    return Ok(());
+            let mut total_size = 0;
+            for path in &self.session.flagged_files {
+                if let Ok(data) = path.metadata() {
+                    total_size += data.size();
                 }
             }
-            match prot.initiate_send(&mut *self.connection, &files).await {
-                Ok(mut state) => {
-                    /*     let mut c = BlockingConnection {
-                        conn: &mut self.connection,
-                    };*/
-                    while !state.is_finished {
-                        if let Err(e) = prot.update_transfer(&mut *self.connection, &mut state).await {
-                            log::error!("Error while updating file transfer with {:?} : {}", protocol, e);
-                            self.display_text(IceText::TransferAborted, display_flags::NEWLINE).await?;
-                            break;
-                        }
+            self.display_text(IceText::BatchDownloadSize, display_flags::DEFAULT).await?;
+            self.set_color(TerminalTarget::Both, IcbColor::dos_light_green()).await?;
+            self.println(TerminalTarget::Both, &format!(" {}", humanize_bytes_decimal!(total_size).to_string()))
+                .await?;
+
+            self.display_text(IceText::BatchProtocol, display_flags::DEFAULT).await?;
+            self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
+            self.println(TerminalTarget::Both, &p_descr).await?;
+            self.display_text(IceText::ReadyToSendBatch, display_flags::NEWLINE | display_flags::LFAFTER)
+                .await?;
+
+            let input = self
+                .input_field(
+                    IceText::GoodbyeAfterDownload,
+                    1,
+                    &DL_LISTMASK,
+                    &"",
+                    None,
+                    display_flags::NEWLINE | display_flags::UPCASE | display_flags::FIELDLEN,
+                )
+                .await?;
+
+            match input.as_str() {
+                "A" => {
+                    do_dl = false;
+                    break;
+                }
+                "E" => {
+                    self.edit_dl_batch().await?;
+                }
+                "G" => {
+                    goodbye_after_dl = true;
+                    break;
+                }
+                "L" => {
+                    self.list_dl_batch().await?;
+                }
+                "P" => {
+                    let protocol = self.ask_protocols(&protocol_str).await?;
+
+                    if !protocol.is_empty() {
+                        protocol_str = protocol;
                     }
                 }
-                Err(e) => {
-                    log::error!("Error while initiating file transfer with {:?} : {}", protocol, e);
-                    self.println(TerminalTarget::Both, &format!("Error: {}", e)).await?;
+                _ => {
+                    break;
                 }
             }
-        } else {
-            self.println(TerminalTarget::Both, "Protocol not found.").await?;
+        }
+        if do_dl {
+            self.display_text(IceText::SendingFiles, display_flags::NEWLINE).await?;
+
+            if let Some(protocol) = &protocol {
+                let mut prot = protocol.create();
+                let files: Vec<PathBuf> = self.session.flagged_files.drain(..).collect();
+                for f in &files {
+                    if !f.exists() {
+                        log::error!("File not found: {:?}", f);
+                        self.session.op_text = f.file_name().unwrap().to_string_lossy().to_string();
+                        self.display_text(IceText::NotFoundOnDisk, display_flags::NEWLINE).await?;
+                        self.new_line().await?;
+                        self.press_enter().await?;
+                        return Ok(());
+                    }
+                }
+                match prot.initiate_send(&mut *self.connection, &files).await {
+                    Ok(mut state) => {
+                        while !state.is_finished {
+                            if let Err(e) = prot.update_transfer(&mut *self.connection, &mut state).await {
+                                log::error!("Error while updating file transfer with {:?} : {}", protocol, e);
+                                self.display_text(IceText::TransferAborted, display_flags::NEWLINE).await?;
+                                break;
+                            }
+                        }
+                        self.display_text(IceText::BatchTransferEnded, display_flags::LFBEFORE).await?;
+                        self.transfer_statistics.downloaded_bytes = state.send_state.total_bytes_transfered as usize;
+                        self.transfer_statistics.downloaded_files = state.send_state.finished_files.len();
+                        self.transfer_statistics.downloaded_cps = state.send_state.get_bps() as usize;
+                        self.display_text(IceText::BatchSend, display_flags::LFBEFORE).await?;
+                    }
+                    Err(e) => {
+                        log::error!("Error while initiating file transfer with {:?} : {}", protocol, e);
+                        self.println(TerminalTarget::Both, &format!("Error: {}", e)).await?;
+                    }
+                }
+            } else {
+                self.println(TerminalTarget::Both, "Protocol not found.").await?;
+            }
+
+            if goodbye_after_dl {
+                self.goodbye().await?;
+            }
         }
         self.new_line().await?;
         self.press_enter().await?;
         Ok(())
     }
+
+    #[async_recursion(?Send)]
+    async fn edit_dl_batch(&mut self) -> Res<()> {
+        self.new_line().await?;
+
+        loop {
+            let input = self
+                .input_field(
+                    IceText::EditBatch,
+                    1,
+                    &DL_EDITMASK,
+                    &"",
+                    None,
+                    display_flags::NEWLINE | display_flags::UPCASE | display_flags::FIELDLEN,
+                )
+                .await?;
+
+            match input.as_str() {
+                "A" => {
+                    self.new_line().await?;
+                    self.flag_files_cmd(true).await?;
+                }
+                "R" => {
+                    self.remove_dl_batch().await?;
+                }
+                "L" => {
+                    self.list_dl_batch().await?;
+                }
+                _ => {
+                    break;
+                }
+            }
+        }
+        Ok(())
+    }
+
+    async fn remove_dl_batch(&mut self) -> Res<()> {
+        self.session.op_text = format!("1-{}", self.session.flagged_files.len());
+        let input = self
+            .input_field(
+                IceText::RemoveFileNumber,
+                16,
+                &MASK_NUM,
+                &"",
+                None,
+                display_flags::NEWLINE | display_flags::UPCASE | display_flags::LFBEFORE,
+            )
+            .await?;
+        self.session.push_tokens(&input);
+
+        let mut remove = Vec::new();
+        while let Some(token) = self.session.tokens.pop_front() {
+            if let Ok(num) = token.parse::<usize>() {
+                if num == 0 {
+                    continue;
+                }
+                if let Some(path) = &self.session.flagged_files.get(num - 1) {
+                    remove.push(num - 1);
+                    self.session.op_text = path.file_name().unwrap_or_default().to_string_lossy().to_string();
+                    self.display_text(IceText::RemovedFile, display_flags::NEWLINE).await?;
+                }
+            }
+        }
+        remove.sort_by(|a, b| b.cmp(a));
+        for r in remove {
+            self.session.flagged_files.remove(r);
+        }
+        self.new_line().await?;
+        Ok(())
+    }
+    async fn list_dl_batch(&mut self) -> Res<()> {
+        self.new_line().await?;
+        for (i, path) in self.session.flagged_files.clone().iter().enumerate() {
+            let size = if let Ok(data) = path.metadata() { data.size() } else { 0 };
+            self.display_text(IceText::FileSelected, display_flags::DEFAULT).await?;
+            self.set_color(TerminalTarget::Both, IcbColor::dos_light_green()).await?;
+
+            let number = format!("({})", i + 1);
+            self.print(TerminalTarget::Both, &format!("{number:<5}{:>8} ", humanize_bytes_decimal!(size).to_string()))
+                .await?;
+            self.println(TerminalTarget::Both, &format!("{}", path.file_name().unwrap_or_default().to_string_lossy()))
+                .await?;
+        }
+        self.new_line().await?;
+
+        Ok(())
+    }
 }
+
+const DL_LISTMASK: &str = "AEGLP";
+const DL_EDITMASK: &str = "ARL";
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/f_show_file_directories.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/f_show_file_directories.rs
index 604e2f0d..c975f9b1 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/f_show_file_directories.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/f_show_file_directories.rs
@@ -88,7 +88,7 @@ impl IcyBoardState {
                         }
                     }
                     "F" | "FL" | "FLA" | "FLAG" => {
-                        self.flag_files().await?;
+                        self.flag_files_cmd(false).await?;
                     }
                     "L" => {
                         self.find_files_cmd().await?;
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/flag_flag_files.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/flag_flag_files.rs
index 40e5e0a9..3d49fef3 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/flag_flag_files.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/flag_flag_files.rs
@@ -10,18 +10,22 @@ use crate::{
 };
 
 impl IcyBoardState {
-    pub async fn flag_files(&mut self) -> Res<()> {
+    pub async fn flag_files_cmd(&mut self, show_flagged: bool) -> Res<()> {
         // flag
         let input = if let Some(token) = self.session.tokens.pop_front() {
             token
         } else {
             self.input_field(
-                IceText::FlagForDownload,
+                if show_flagged {
+                    IceText::FileNameToDownloadBatch
+                } else {
+                    IceText::FlagForDownload
+                },
                 60,
                 &MASK_ASCII,
                 &"hlpflag",
                 None,
-                display_flags::NEWLINE | display_flags::UPCASE | display_flags::LFAFTER | display_flags::HIGHASCII,
+                display_flags::NEWLINE | display_flags::UPCASE | display_flags::LFAFTER | display_flags::LFBEFORE | display_flags::HIGHASCII,
             )
             .await?
         };
@@ -72,14 +76,15 @@ impl IcyBoardState {
                     continue;
                 }
 
-                if !self.session.flagged_files.insert(file) {
+                if self.session.flagged_files.contains(&file) {
                     self.session.op_text = name;
                     self.display_text(IceText::DuplicateBatchFile, display_flags::NEWLINE).await?;
                     continue;
                 }
+                self.session.flagged_files.push(file);
 
                 let count = self.session.flagged_files.len();
-                self.set_color(TerminalTarget::Both, IcbColor::Dos(10)).await?;
+                self.set_color(TerminalTarget::Both, IcbColor::dos_light_green()).await?;
                 let nr: String = format!("({})", count);
                 self.println(
                     TerminalTarget::Both,
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/l_find_files.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/l_find_files.rs
index 83c53c07..a60dced7 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/l_find_files.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/l_find_files.rs
@@ -106,7 +106,7 @@ impl IcyBoardState {
 
         self.display_text(IceText::ScanningDirectory, display_flags::DEFAULT).await?;
         self.print(TerminalTarget::Both, &format!(" {} ", area + 1)).await?;
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(10)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_light_green()).await?;
         self.print(TerminalTarget::Both, &format!("({})", self.session.current_conference.directories[area].name))
             .await?;
         self.new_line().await?;
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/lang_set_language.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/lang_set_language.rs
index 329089ab..5feba4e8 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/lang_set_language.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/lang_set_language.rs
@@ -45,7 +45,7 @@ impl IcyBoardState {
         self.display_text(IceText::LanguageAvailable, display_flags::NEWLINE | display_flags::LFAFTER)
             .await?;
 
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         for line in languages {
             self.print(TerminalTarget::Both, &line).await?;
             self.new_line().await?;
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/q_quick_message_scan.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/q_quick_message_scan.rs
index d922f545..3c05e2f2 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/q_quick_message_scan.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/q_quick_message_scan.rs
@@ -102,7 +102,7 @@ impl IcyBoardState {
 
         self.display_text(IceText::QuickScanHeader, display_flags::NEWLINE).await?;
 
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         for i in number..message_base.active_messages() {
             match message_base.read_header(i) {
                 Ok(header) => {
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/s_take_survey.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/s_take_survey.rs
index 21d6bab3..72e77b77 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/s_take_survey.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/s_take_survey.rs
@@ -168,7 +168,7 @@ impl IcyBoardState {
                 };
                 if txt.eq_ignore_ascii_case(&self.session.yes_char.to_string()) {
                     for question in &lines[start_line..] {
-                        self.set_color(TerminalTarget::Both, IcbColor::Dos(14)).await?;
+                        self.set_color(TerminalTarget::Both, IcbColor::dos_yellow()).await?;
                         self.print(TerminalTarget::Both, question).await?;
                         self.new_line().await?;
                         self.reset_color(TerminalTarget::Both).await?;
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/t_set_transfer_protocol.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/t_set_transfer_protocol.rs
index 0157006c..5da5c0e4 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/t_set_transfer_protocol.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/t_set_transfer_protocol.rs
@@ -20,7 +20,7 @@ impl IcyBoardState {
             String::new()
         };
 
-        let protocol = self.ask_protocols(cur_protocol).await?;
+        let protocol = self.ask_protocols(&cur_protocol).await?;
         if !protocol.is_empty() {
             let selected_protocol = protocol.to_ascii_uppercase();
 
@@ -35,7 +35,7 @@ impl IcyBoardState {
             if let Some(user) = &mut self.session.current_user {
                 user.protocol = selected_protocol;
             }
-            self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+            self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
             self.print(TerminalTarget::Both, &txt).await?;
             self.new_line().await?;
             self.new_line().await?;
@@ -45,7 +45,7 @@ impl IcyBoardState {
         Ok(())
     }
 
-    pub async fn ask_protocols(&mut self, cur_protocol: String) -> Res<String> {
+    pub async fn ask_protocols(&mut self, cur_protocol: &str) -> Res<String> {
         let mut protocols = Vec::new();
         self.new_line().await?;
         for protocol in self.get_board().await.protocols.iter() {
@@ -71,7 +71,7 @@ impl IcyBoardState {
             ));
         }
 
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         for line in protocols {
             self.print(TerminalTarget::Both, &line).await?;
             self.new_line().await?;
@@ -83,7 +83,7 @@ impl IcyBoardState {
                 &MASK_ALNUM,
                 "",
                 Some(cur_protocol.to_string()),
-                display_flags::NEWLINE | display_flags::LFBEFORE | display_flags::LFAFTER | display_flags::UPCASE | display_flags::FIELDLEN,
+                display_flags::NEWLINE | display_flags::LFBEFORE | display_flags::UPCASE | display_flags::FIELDLEN,
             )
             .await?;
         Ok(protocol)
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/w_write_settings.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/w_write_settings.rs
index b09df06b..49d581eb 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/w_write_settings.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/w_write_settings.rs
@@ -129,7 +129,8 @@ impl IcyBoardState {
         }
 
         if settings.ask_xfer_protocol {
-            let protocol = self.ask_protocols("N".to_string()).await?;
+            let protocol = self.ask_protocols("N").await?;
+            self.new_line().await?;
             if !protocol.is_empty() {
                 new_user.protocol = protocol;
             } else {
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/who_display_nodes.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/who_display_nodes.rs
index be02849f..996a58c4 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/who_display_nodes.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/who_display_nodes.rs
@@ -22,7 +22,7 @@ impl IcyBoardState {
                 }
             }
         }
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(11)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_cyan()).await?;
         self.println(TerminalTarget::Both, &lines.join("\r\n")).await?;
         self.new_line().await?;
         Ok(())
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/y_your_mail_scan.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/y_your_mail_scan.rs
index 349e7cd3..e54d8128 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/y_your_mail_scan.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/y_your_mail_scan.rs
@@ -148,14 +148,14 @@ impl IcyBoardState {
             }
         }
         if res.msg_to > 0 {
-            self.set_color(TerminalTarget::Both, IcbColor::Dos(15)).await?;
+            self.set_color(TerminalTarget::Both, IcbColor::dos_white()).await?;
         } else {
             self.reset_color(TerminalTarget::Both).await?;
         }
         self.print(TerminalTarget::Both, &format!("{:>6}", res.msg_to)).await?;
 
         if res.msg_from > 0 {
-            self.set_color(TerminalTarget::Both, IcbColor::Dos(15)).await?;
+            self.set_color(TerminalTarget::Both, IcbColor::dos_white()).await?;
         } else {
             self.reset_color(TerminalTarget::Both).await?;
         }
diff --git a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/z_zippy_directory_scan.rs b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/z_zippy_directory_scan.rs
index 06b85658..66fe7286 100644
--- a/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/z_zippy_directory_scan.rs
+++ b/crates/icy_board_engine/src/icy_board/state/user_commands/pcb/z_zippy_directory_scan.rs
@@ -102,7 +102,7 @@ impl IcyBoardState {
 
         self.display_text(IceText::ScanningDirectory, display_flags::DEFAULT).await?;
         self.print(TerminalTarget::Both, &format!(" {} ", area + 1)).await?;
-        self.set_color(TerminalTarget::Both, IcbColor::Dos(10)).await?;
+        self.set_color(TerminalTarget::Both, IcbColor::dos_light_green()).await?;
         self.print(TerminalTarget::Both, &format!("({})", self.session.current_conference.directories[area].name))
             .await?;
         self.new_line().await?;
diff --git a/crates/icy_board_engine/src/vm/statements/predefined_procedures.rs b/crates/icy_board_engine/src/vm/statements/predefined_procedures.rs
index c06ba193..c5104107 100644
--- a/crates/icy_board_engine/src/vm/statements/predefined_procedures.rs
+++ b/crates/icy_board_engine/src/vm/statements/predefined_procedures.rs
@@ -256,7 +256,7 @@ pub async fn log(vm: &mut VirtualMachine<'_>, args: &[PPEExpr]) -> Res<()> {
 
 pub async fn input(vm: &mut VirtualMachine<'_>, args: &[PPEExpr]) -> Res<()> {
     let prompt = vm.eval_expr(&args[0]).await?.as_string();
-    let color = IcbColor::Dos(14);
+    let color = IcbColor::dos_yellow();
     let d = get_default_string(vm, &args[1]).await;
     let output = vm
         .icy_board_state