├── README.md ├── sender.rs ├── receiver.rs └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # Rusty-Telephone 🎧 2 | 3 | Data exfiltration tool that transmits files through audio loopback devices using frequency-shift keying (FSK) modulation. 4 | 5 | ## Overview 6 | 7 | Rusty-Telephone encodes files into audio signals and transmits them between systems using audio loopback. It uses: 8 | - FSK modulation with multiple frequencies for data encoding 9 | - Reed-Solomon error correction 10 | - SHA-256 checksums for data integrity 11 | - Sync sequences and preambles for reliable transmission 12 | - Digital signal processing for audio analysis 13 | 14 | ## Prerequisites 15 | 16 | - Rust toolchain (latest stable) 17 | - Audio loopback driver: 18 | - macOS: [BlackHole](https://github.com/ExistentialAudio/BlackHole) 19 | - Windows: [Virtual Audio Cable](https://vb-audio.com/Cable/) 20 | - Linux: [PulseAudio null sink](https://www.freedesktop.org/wiki/Software/PulseAudio/) 21 | 22 | ## Example 23 | - Sender: 24 | * ![image](https://github.com/user-attachments/assets/bf577c6d-49ff-4f96-859d-4866bd985903) 25 | 26 | - Receiver: 27 | * ![image](https://github.com/user-attachments/assets/92da5343-73bf-4a6b-ad9a-685d9bf615bf) 28 | 29 | 30 | ## Installation 31 | 32 | 1. Clone the repository: 33 | ```bash 34 | git clone https://github.com/referefref/rusty-telephone 35 | cd rusty-telephone 36 | ``` 37 | 38 | 2. Build sender and receiver: 39 | 40 | **macOS/Linux:** 41 | ```bash 42 | cargo build --release -p sender 43 | cargo build --release -p receiver 44 | ``` 45 | 46 | **Windows:** 47 | ```bash 48 | cargo build --release -p sender 49 | cargo build --release -p receiver 50 | ``` 51 | 52 | Binaries will be in `target/release/`. 53 | 54 | ## Usage 55 | 56 | 1. Set up audio loopback: 57 | - **macOS**: Install BlackHole or similar and select it as output device 58 | - **Windows**: Install Virtual Audio Cable or similar and configure it 59 | - **Linux**: Create null sink: `pactl load-module module-null-sink sink_name=loopback` 60 | 61 | 2. Start receiver: 62 | ```bash 63 | ./receiver --output-dir /path/to/output 64 | ``` 65 | 66 | 3. Start sender: 67 | ```bash 68 | ./sender --input /path/to/file 69 | ``` 70 | 71 | 4. Press Enter in sender window to begin transmission 72 | 73 | ## Technical Details 74 | 75 | - Sample rate: 48kHz 76 | - Bit duration: 2ms 77 | - FSK frequencies: 78 | - Sync: 240Hz 79 | - Preamble: 600Hz 80 | - Data '0': 2000Hz 81 | - Data '1': 4000Hz 82 | - Start marker: 1000Hz 83 | - End marker: 6000Hz 84 | 85 | ### Dependencies 86 | 87 | ```toml 88 | # sender/Cargo.toml 89 | [dependencies] 90 | rodio = "0.17" 91 | bytes = "1.4" 92 | sha2 = "0.10" 93 | hex = "0.4" 94 | anyhow = "1.0" 95 | clap = { version = "4.3", features = ["derive"] } 96 | indicatif = "0.17" 97 | console = "0.15" 98 | reed-solomon = "0.2.1" 99 | 100 | # receiver/Cargo.toml 101 | [dependencies] 102 | cpal = "0.15" 103 | rustfft = "6.1" 104 | bytes = "1.4" 105 | sha2 = "0.10" 106 | hex = "0.4" 107 | anyhow = "1.0" 108 | clap = { version = "4.3", features = ["derive"] } 109 | ringbuf = "0.3" 110 | indicatif = "0.17" 111 | console = "0.15" 112 | reed-solomon = "0.2.1" 113 | ``` 114 | -------------------------------------------------------------------------------- /sender.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | use std::time::Duration; 3 | use std::thread; 4 | use anyhow::{Result, Context}; 5 | use clap::Parser; 6 | use rodio::{OutputStream, Sink, Source}; 7 | use sha2::{Sha256, Digest}; 8 | use indicatif::{ProgressBar, ProgressStyle}; 9 | use console::style; 10 | use reed_solomon::Encoder; 11 | 12 | const SAMPLE_RATE: u32 = 48000; 13 | const BIT_DURATION_MS: u64 = 2; 14 | const AMPLITUDE: f32 = 0.8; 15 | const SYNC_DURATION_MS: u64 = 1000; 16 | const SYNC_FREQUENCY: f32 = 240.0; 17 | const PREAMBLE_DURATION_MS: u64 = 500; 18 | const PREAMBLE_FREQUENCY: f32 = 600.0; 19 | 20 | #[derive(Parser)] 21 | #[command(author, version, about, long_about = None)] 22 | struct Args { 23 | /// Input file to transmit 24 | #[arg(short, long)] 25 | input: PathBuf, 26 | } 27 | 28 | #[derive(Clone, Copy, Debug)] 29 | struct FrequencyMap { 30 | zero: f32, 31 | one: f32, 32 | start: f32, 33 | end: f32, 34 | } 35 | 36 | impl Default for FrequencyMap { 37 | fn default() -> Self { 38 | Self { 39 | zero: 2000.0, 40 | one: 4000.0, 41 | start: 1000.0, 42 | end: 6000.0, 43 | } 44 | } 45 | } 46 | 47 | struct TransmissionStats { 48 | total_bytes: usize, 49 | start_time: std::time::Instant, 50 | } 51 | 52 | impl TransmissionStats { 53 | fn new(total_bytes: usize) -> Self { 54 | Self { 55 | total_bytes, 56 | start_time: std::time::Instant::now(), 57 | } 58 | } 59 | 60 | fn print_summary(&self) { 61 | let duration = self.start_time.elapsed(); 62 | let rate = (self.total_bytes as f64) / duration.as_secs_f64(); 63 | 64 | println!("\n{}", style("Transmission Summary:").cyan().bold()); 65 | println!("├─ Total bytes: {}", style(self.total_bytes).green()); 66 | println!("├─ Duration: {:.2}s", style(duration.as_secs_f64()).green()); 67 | println!("└─ Transfer rate: {:.2} bytes/sec", style(rate).green()); 68 | } 69 | } 70 | 71 | struct SineWaveSource { 72 | frequency: f32, 73 | sample_rate: u32, 74 | amplitude: f32, 75 | num_samples: usize, 76 | current_sample: usize, 77 | } 78 | 79 | impl SineWaveSource { 80 | fn new(frequency: f32, duration_ms: u64, sample_rate: u32, amplitude: f32) -> Self { 81 | let num_samples = (sample_rate as f64 * (duration_ms as f64 / 1000.0)) as usize; 82 | Self { 83 | frequency, 84 | sample_rate, 85 | amplitude, 86 | num_samples, 87 | current_sample: 0, 88 | } 89 | } 90 | } 91 | 92 | impl Iterator for SineWaveSource { 93 | type Item = f32; 94 | 95 | fn next(&mut self) -> Option { 96 | if self.current_sample >= self.num_samples { 97 | return None; 98 | } 99 | 100 | let t = self.current_sample as f32 / self.sample_rate as f32; 101 | let sample = (2.0 * std::f32::consts::PI * self.frequency * t).sin() * self.amplitude; 102 | self.current_sample += 1; 103 | Some(sample) 104 | } 105 | } 106 | 107 | impl Source for SineWaveSource { 108 | fn current_frame_len(&self) -> Option { 109 | Some(self.num_samples - self.current_sample) 110 | } 111 | 112 | fn channels(&self) -> u16 { 113 | 1 114 | } 115 | 116 | fn sample_rate(&self) -> u32 { 117 | self.sample_rate 118 | } 119 | 120 | fn total_duration(&self) -> Option { 121 | Some(std::time::Duration::from_millis( 122 | (self.num_samples as f64 / self.sample_rate as f64 * 1000.0) as u64, 123 | )) 124 | } 125 | } 126 | 127 | struct AudioEncoder { 128 | sample_rate: u32, 129 | frequencies: FrequencyMap, 130 | progress_bar: ProgressBar, 131 | stats: TransmissionStats, 132 | } 133 | 134 | impl AudioEncoder { 135 | fn new(sample_rate: u32, total_bytes: usize) -> Self { 136 | let progress_bar = ProgressBar::new(total_bytes as u64); 137 | progress_bar.set_style( 138 | ProgressStyle::default_bar() 139 | .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})") 140 | .expect("Invalid progress bar template") 141 | .progress_chars("#>-") 142 | ); 143 | 144 | Self { 145 | sample_rate, 146 | frequencies: FrequencyMap::default(), 147 | progress_bar, 148 | stats: TransmissionStats::new(total_bytes), 149 | } 150 | } 151 | 152 | fn send_sync_sequence(&self, sink: &Sink) { 153 | println!("{}", style("\nSending sync sequence...").yellow()); 154 | 155 | // Send silence to separate sync from data 156 | sink.append(SineWaveSource::new(0.0, 400, self.sample_rate, 0.0)); 157 | 158 | // Send sync tone (longer duration) 159 | sink.append(SineWaveSource::new( 160 | SYNC_FREQUENCY, 161 | SYNC_DURATION_MS, 162 | self.sample_rate, 163 | AMPLITUDE 164 | )); 165 | 166 | // Send silence to separate sync from data 167 | sink.append(SineWaveSource::new(0.0, 200, self.sample_rate, 0.0)); 168 | 169 | // Wait for sync to complete 170 | thread::sleep(Duration::from_millis(SYNC_DURATION_MS + 400)); 171 | } 172 | 173 | fn send_preamble(&self, sink: &Sink) { 174 | println!("{}", style("\nSending preamble...").yellow()); 175 | 176 | // Send preamble tone 177 | sink.append(SineWaveSource::new( 178 | PREAMBLE_FREQUENCY, 179 | PREAMBLE_DURATION_MS, 180 | self.sample_rate, 181 | AMPLITUDE 182 | )); 183 | 184 | // Send silence to separate preamble from data 185 | sink.append(SineWaveSource::new(0.0, 400, self.sample_rate, 0.0)); 186 | 187 | // Wait for preamble to complete 188 | thread::sleep(Duration::from_millis(PREAMBLE_DURATION_MS + 800)); 189 | } 190 | 191 | fn encode_bytes(&mut self, data: &[u8], sink: &Sink) { 192 | // Initial silence 193 | sink.append(SineWaveSource::new( 194 | 0.0, 195 | BIT_DURATION_MS * 4, 196 | self.sample_rate, 197 | 0.0 198 | )); 199 | 200 | // Synchronization sequence 201 | for _ in 0..4 { // Increased from 3 to 4 202 | // Start marker 203 | sink.append(SineWaveSource::new( 204 | self.frequencies.start, 205 | BIT_DURATION_MS * 4, 206 | self.sample_rate, 207 | AMPLITUDE 208 | )); 209 | 210 | // Silence gap 211 | sink.append(SineWaveSource::new( 212 | 0.0, 213 | BIT_DURATION_MS * 2, 214 | self.sample_rate, 215 | 0.0 216 | )); 217 | } 218 | 219 | // Preamble - fixed pattern 0x55 (alternating 1s and 0s) 220 | for _ in 0..8 { 221 | sink.append(SineWaveSource::new( 222 | self.frequencies.one, 223 | BIT_DURATION_MS, 224 | self.sample_rate, 225 | AMPLITUDE 226 | )); 227 | 228 | sink.append(SineWaveSource::new( 229 | self.frequencies.zero, 230 | BIT_DURATION_MS, 231 | self.sample_rate, 232 | AMPLITUDE 233 | )); 234 | } 235 | 236 | // Add a clear separator after the header 237 | let header_end_marker = b"|END|"; 238 | let mut transmission_data = Vec::new(); 239 | 240 | // Add header 241 | transmission_data.extend_from_slice(data); 242 | transmission_data.extend_from_slice(header_end_marker); 243 | 244 | // Add extra silence between header and data 245 | sink.append(SineWaveSource::new( 246 | 0.0, 247 | BIT_DURATION_MS * 8, 248 | self.sample_rate, 249 | 0.0 250 | )); 251 | 252 | // Data with byte boundaries 253 | for (i, &byte) in data.iter().enumerate() { 254 | // Byte start marker 255 | sink.append(SineWaveSource::new( 256 | self.frequencies.one, 257 | BIT_DURATION_MS, 258 | self.sample_rate, 259 | AMPLITUDE 260 | )); 261 | 262 | // Data bits 263 | for bit_pos in (0..8).rev() { 264 | let bit = (byte >> bit_pos) & 1; 265 | let freq = if bit == 1 { 266 | self.frequencies.one 267 | } else { 268 | self.frequencies.zero 269 | }; 270 | 271 | sink.append(SineWaveSource::new( 272 | freq, 273 | BIT_DURATION_MS, 274 | self.sample_rate, 275 | AMPLITUDE 276 | )); 277 | } 278 | 279 | // Byte end marker 280 | sink.append(SineWaveSource::new( 281 | self.frequencies.zero, 282 | BIT_DURATION_MS, 283 | self.sample_rate, 284 | AMPLITUDE 285 | )); 286 | 287 | self.progress_bar.set_position((i + 1) as u64); 288 | } 289 | 290 | // End sequence 291 | sink.append(SineWaveSource::new( 292 | 0.0, 293 | BIT_DURATION_MS * 16, 294 | self.sample_rate, 295 | 0.0 296 | )); 297 | 298 | for _ in 0..4 { 299 | sink.append(SineWaveSource::new( 300 | self.frequencies.end, 301 | BIT_DURATION_MS * 16, 302 | self.sample_rate, 303 | AMPLITUDE * 1.2 304 | )); 305 | 306 | sink.append(SineWaveSource::new( 307 | 0.0, 308 | BIT_DURATION_MS * 2, 309 | self.sample_rate, 310 | 0.0 311 | )); 312 | } 313 | } 314 | } 315 | 316 | struct FileTransfer { 317 | encoder: AudioEncoder, 318 | } 319 | 320 | impl FileTransfer { 321 | fn new(total_bytes: usize) -> Self { 322 | Self { 323 | encoder: AudioEncoder::new(SAMPLE_RATE, total_bytes), 324 | } 325 | } 326 | 327 | fn create_header(&self, filename: &str, file_size: u64, checksum: &str) -> String { 328 | format!("{}|{}|{}", filename, file_size, checksum) 329 | } 330 | 331 | fn calculate_checksum(&self, data: &[u8]) -> String { 332 | let mut hasher = Sha256::new(); 333 | hasher.update(data); 334 | hex::encode(hasher.finalize()) 335 | } 336 | 337 | fn transmit_file(&mut self, input_path: &PathBuf) -> Result<()> { 338 | println!("{}", style("\nInitializing file transfer...").cyan().bold()); 339 | 340 | // Read file 341 | let file_data = std::fs::read(input_path) 342 | .context("Failed to read input file")?; 343 | 344 | // Create header 345 | let filename = input_path.file_name() 346 | .context("Invalid filename")? 347 | .to_string_lossy(); 348 | let checksum = self.calculate_checksum(&file_data); 349 | let header = self.create_header(&filename, file_data.len() as u64, &checksum); 350 | 351 | println!("File: {}", style(&filename).green()); 352 | println!("Size: {} bytes", style(file_data.len()).green()); 353 | println!("Checksum: {}", style(&checksum).green()); 354 | 355 | // Initialize audio output 356 | let (_stream, stream_handle) = OutputStream::try_default() 357 | .context("Failed to initialize audio output")?; 358 | let sink = Sink::try_new(&stream_handle) 359 | .context("Failed to create audio sink")?; 360 | 361 | println!("\n{}", style("Waiting for receiver...").yellow()); 362 | println!("Press Enter when ready to start transmission"); 363 | let mut input = String::new(); 364 | std::io::stdin().read_line(&mut input)?; 365 | 366 | // Send sync sequence 367 | self.encoder.send_sync_sequence(&sink); 368 | 369 | // Send preamble 370 | self.encoder.send_preamble(&sink); 371 | 372 | println!("{}", style("\nStarting transmission...").green()); 373 | 374 | // Prepare the complete transmission data 375 | let mut transmission_data = Vec::new(); 376 | 377 | // Add header 378 | transmission_data.extend_from_slice(header.as_bytes()); 379 | 380 | // Add |END| marker after header 381 | transmission_data.extend_from_slice(b"|END|"); 382 | 383 | // Add file data 384 | transmission_data.extend_from_slice(&file_data); 385 | 386 | // Apply Reed-Solomon encoding 387 | let rs = Encoder::new(32); 388 | let encoded_data: Vec = transmission_data 389 | .chunks(223) 390 | .flat_map(|chunk| { 391 | let mut padded_chunk = chunk.to_vec(); 392 | padded_chunk.resize(223, 0); // Pad with zeros if necessary 393 | rs.encode(&padded_chunk).data().to_vec() 394 | }) 395 | .collect(); 396 | 397 | // Debug print the first part of the transmission data 398 | println!("\nTransmission data preview:"); 399 | for (i, chunk) in transmission_data[..100.min(transmission_data.len())].chunks(16).enumerate() { 400 | print!("{:04x}: ", i * 16); 401 | for byte in chunk { 402 | print!("{:02x} ", byte); 403 | } 404 | print!(" "); 405 | for &byte in chunk { 406 | print!("{}", if byte.is_ascii_graphic() || byte == b' ' { 407 | byte as char 408 | } else { 409 | '.' 410 | }); 411 | } 412 | println!(); 413 | } 414 | 415 | self.encoder.encode_bytes(&encoded_data, &sink); 416 | 417 | sink.sleep_until_end(); 418 | self.encoder.stats.print_summary(); 419 | 420 | println!("\n{}", style("Transmission complete!").green().bold()); 421 | 422 | Ok(()) 423 | } 424 | } 425 | 426 | fn main() -> Result<()> { 427 | let args = Args::parse(); 428 | let total_bytes = std::fs::metadata(&args.input)?.len() as usize; 429 | let mut transfer = FileTransfer::new(total_bytes); 430 | 431 | println!("{}", style("Audio File Transfer").cyan().bold()); 432 | transfer.transmit_file(&args.input)?; 433 | 434 | Ok(()) 435 | } 436 | -------------------------------------------------------------------------------- /receiver.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | use std::sync::atomic::{AtomicBool, AtomicUsize}; 3 | use std::sync::Arc; 4 | use std::thread; 5 | use std::time::{Duration, Instant}; 6 | use anyhow::{Result, Context}; 7 | use clap::Parser; 8 | use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; 9 | use rustfft::{FftPlanner, num_complex::Complex}; 10 | use sha2::{Sha256, Digest}; 11 | use ringbuf::HeapRb; 12 | use indicatif::{ProgressBar, ProgressStyle, MultiProgress}; 13 | use console::style; 14 | 15 | const SAMPLE_RATE: u32 = 48000; 16 | const BIT_DURATION_MS: u64 = 2; 17 | const SYNC_FREQUENCY: f32 = 240.0; 18 | const SYNC_DURATION_MS: u64 = 1000; 19 | const PREAMBLE_FREQUENCY: f32 = 600.0; 20 | const PREAMBLE_DURATION_MS: u64 = 500; 21 | const FREQUENCY_TOLERANCE: f32 = 100.0; 22 | 23 | #[derive(Parser)] 24 | #[command(author, version, about, long_about = None)] 25 | struct Args { 26 | #[arg(short, long, default_value = ".")] 27 | output_dir: PathBuf, 28 | } 29 | 30 | #[derive(Clone, Copy, Debug)] 31 | struct FrequencyMap { 32 | zero: f32, 33 | one: f32, 34 | start: f32, 35 | end: f32, 36 | } 37 | 38 | impl Default for FrequencyMap { 39 | fn default() -> Self { 40 | Self { 41 | zero: 2000.0, 42 | one: 4000.0, 43 | start: 1000.0, 44 | end: 6000.0, 45 | } 46 | } 47 | } 48 | 49 | #[derive(Clone, Copy, Debug)] 50 | struct FrequencyDetection { 51 | frequency: f32, 52 | amplitude: f32, 53 | rms: f32, 54 | } 55 | 56 | #[derive(Debug)] 57 | enum DecodeState { 58 | WaitingForSync, 59 | WaitingForPreamble, 60 | WaitingForByteStart, 61 | ReadingBits { current_byte: u8, bits_read: usize }, 62 | WaitingForByteEnd, 63 | } 64 | 65 | struct ReceiveStats { 66 | total_samples: usize, 67 | valid_chunks: usize, 68 | start_time: std::time::Instant, 69 | frequencies_detected: Vec<(usize, FrequencyDetection)>, 70 | } 71 | 72 | impl ReceiveStats { 73 | fn new() -> Self { 74 | Self { 75 | total_samples: 0, 76 | valid_chunks: 0, 77 | start_time: std::time::Instant::now(), 78 | frequencies_detected: Vec::new(), 79 | } 80 | } 81 | 82 | fn print_summary(&self) { 83 | let duration = self.start_time.elapsed(); 84 | 85 | println!("\n{}", style("Reception Summary:").cyan().bold()); 86 | println!("├─ Total samples: {}", style(self.total_samples).green()); 87 | println!("├─ Valid chunks: {}", style(self.valid_chunks).green()); 88 | println!("├─ Duration: {:.2}s", style(duration.as_secs_f64()).green()); 89 | 90 | println!("\n{}", style("Recent frequency detections:").cyan()); 91 | for (chunk, detection) in self.frequencies_detected.iter().rev().take(10).rev() { 92 | println!("Chunk {}: {:.1} Hz (RMS: {:.6}, Amp: {:.6})", 93 | chunk, detection.frequency, detection.rms, detection.amplitude); 94 | } 95 | } 96 | } 97 | 98 | struct AudioDecoder { 99 | sample_rate: u32, 100 | frequencies: FrequencyMap, 101 | fft_planner: FftPlanner, 102 | stats: ReceiveStats, 103 | multi_progress: MultiProgress, 104 | } 105 | 106 | impl AudioDecoder { 107 | fn new(sample_rate: u32) -> Self { 108 | let frequencies = FrequencyMap::default(); 109 | 110 | println!("\n{}", style("Frequency configuration:").cyan()); 111 | println!("├─ Start: {:.1} Hz", frequencies.start); 112 | println!("├─ Zero: {:.1} Hz", frequencies.zero); 113 | println!("├─ One: {:.1} Hz", frequencies.one); 114 | println!("└─ End: {:.1} Hz", frequencies.end); 115 | 116 | Self { 117 | sample_rate, 118 | frequencies, 119 | fft_planner: FftPlanner::new(), 120 | stats: ReceiveStats::new(), 121 | multi_progress: MultiProgress::new(), 122 | } 123 | } 124 | 125 | fn detect_frequency(&mut self, samples: &[f32], chunk_index: usize) -> Option { 126 | if samples.len() < 96 { 127 | return None; 128 | } 129 | 130 | let rms = (samples.iter().map(|x| x * x).sum::() / samples.len() as f32).sqrt(); 131 | // println!("RMS at chunk {}: {:.6}", chunk_index, rms); 132 | 133 | if rms < 0.01 { // Lowered threshold for better sensitivity 134 | return None; 135 | } 136 | 137 | let windowed_samples: Vec> = samples.iter() 138 | .enumerate() 139 | .map(|(i, &x)| { 140 | let window = 0.5 * (1.0 - (2.0 * std::f32::consts::PI * i as f32 141 | / (samples.len() - 1) as f32).cos()); 142 | Complex::new(x * window, 0.0) 143 | }) 144 | .collect(); 145 | 146 | let mut spectrum = windowed_samples; 147 | let fft = self.fft_planner.plan_fft_forward(samples.len()); 148 | fft.process(&mut spectrum); 149 | 150 | let bin_size = 5.0; // Reduced bin size for better frequency resolution 151 | let mut binned_spectrum = vec![0.0f32; (5000.0 / bin_size) as usize]; 152 | 153 | for (i, c) in spectrum.iter().enumerate() { 154 | let freq = i as f32 * self.sample_rate as f32 / samples.len() as f32; 155 | if freq <= 5000.0 { 156 | let bin = (freq / bin_size) as usize; 157 | if bin < binned_spectrum.len() { 158 | binned_spectrum[bin] += c.norm_sqr() as f32; 159 | } 160 | } 161 | } 162 | 163 | let mean_power = binned_spectrum.iter() 164 | .filter(|&&p| p > 0.0) 165 | .sum::() / binned_spectrum.iter().filter(|&&p| p > 0.0).count() as f32; 166 | let threshold = mean_power * 1.5; // Lowered threshold multiplier 167 | 168 | let max_freq = binned_spectrum.iter() 169 | .enumerate() 170 | .filter(|(_, &power)| power > threshold) 171 | .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap()) 172 | .map(|(i, power)| { 173 | let freq = (i as f32 * bin_size) + (bin_size / 2.0); 174 | 175 | if chunk_index % 100 == 0 { 176 | println!("Chunk {}: Detected frequency {:.1} Hz (power: {:.6})", 177 | chunk_index, freq, power); 178 | } 179 | 180 | freq 181 | }); 182 | 183 | if max_freq.is_some() { 184 | self.stats.valid_chunks += 1; 185 | } 186 | 187 | max_freq 188 | } 189 | 190 | fn wait_for_sync(&mut self, samples: &[f32]) -> Option { 191 | self.detect_signal(samples, SYNC_FREQUENCY, SYNC_DURATION_MS, "sync") 192 | } 193 | 194 | fn wait_for_preamble(&mut self, samples: &[f32], start_index: usize) -> Option { 195 | let window_size = (self.sample_rate as f64 * (PREAMBLE_DURATION_MS as f64 / 1000.0)) as usize; 196 | let step_size = window_size / 4; // Smaller steps for more precise detection 197 | 198 | println!("\nPreamble detection parameters:"); 199 | println!("├─ Start index: {}", start_index); 200 | println!("├─ Window size: {}", window_size); 201 | println!("├─ Step size: {}", step_size); 202 | println!("└─ Available samples: {}", samples.len()); 203 | 204 | let spinner = self.multi_progress.add(ProgressBar::new_spinner()); 205 | spinner.set_style(ProgressStyle::default_spinner() 206 | .template("{spinner:.green} {msg}") 207 | .expect("Invalid spinner template")); 208 | 209 | // Skip past the sync signal 210 | let search_start = start_index + (SYNC_DURATION_MS as f32 * SAMPLE_RATE as f32 / 1000.0) as usize; 211 | 212 | for (i, window) in samples[search_start..].windows(window_size).step_by(step_size).enumerate() { 213 | spinner.set_message(format!("Looking for preamble... (window {})", i)); 214 | 215 | if let Some(freq) = self.detect_frequency(window, i) { 216 | println!("Window {}: Found frequency {:.1} Hz", i, freq); 217 | 218 | if (freq - PREAMBLE_FREQUENCY).abs() < FREQUENCY_TOLERANCE { 219 | let absolute_position = search_start + (i * step_size); 220 | spinner.finish_with_message(format!( 221 | "Preamble detected at sample {} (freq: {:.1} Hz)", 222 | absolute_position, freq 223 | )); 224 | return Some(absolute_position + window_size); // Return position after preamble 225 | } 226 | } 227 | 228 | if i % 10 == 0 { 229 | println!("Processed {} windows", i); 230 | } 231 | } 232 | 233 | spinner.finish_with_message("No preamble detected"); 234 | None 235 | } 236 | 237 | fn detect_signal(&mut self, samples: &[f32], target_frequency: f32, duration_ms: u64, signal_name: &str) -> Option { 238 | let samples_per_ms = self.sample_rate as usize / 1000; 239 | let window_size = duration_ms as usize * samples_per_ms; 240 | let step_size = samples_per_ms * 30; // Check every 25ms for more frequent checks 241 | 242 | println!("\n{} {} detection parameters:", style(signal_name).cyan(), style("signal").cyan()); 243 | println!("├─ Frequency: {} Hz", target_frequency); 244 | println!("├─ Duration: {} ms", duration_ms); 245 | println!("├─ Window size: {} samples", window_size); 246 | println!("└─ Tolerance: ±{} Hz", FREQUENCY_TOLERANCE); 247 | println!("├─ Total samples available: {}", samples.len()); 248 | println!("└─ Maximum windows possible: {}", samples.len().saturating_sub(window_size) / step_size + 1); 249 | 250 | let spinner = self.multi_progress.add(ProgressBar::new_spinner()); 251 | spinner.set_style(ProgressStyle::default_spinner() 252 | .template("{spinner:.green} {msg}") 253 | .expect("Invalid spinner template")); 254 | 255 | let max_window_idx = samples.len().saturating_sub(window_size) / step_size; 256 | 257 | println!("Beginning {} signal detection with {} possible windows", signal_name, max_window_idx); 258 | 259 | for (i, window) in samples.windows(window_size).enumerate().step_by(step_size) { 260 | if i >= max_window_idx { 261 | println!("Reached end of safe window range at window {}", i); 262 | break; 263 | } 264 | 265 | spinner.set_message(format!("Listening for {} tone... (window {})", signal_name, i)); 266 | spinner.tick(); 267 | 268 | if let Some(freq) = self.detect_frequency(window, i) { 269 | let freq_match = (freq - target_frequency).abs() < FREQUENCY_TOLERANCE; 270 | 271 | println!("Window {}: Detected frequency = {:.1} Hz, Match = {}", i, freq, freq_match); 272 | 273 | if freq_match { 274 | let start_pos = i * step_size; 275 | spinner.finish_with_message(format!( 276 | "{} signal detected at sample {}! (Frequency: {:.1} Hz)", 277 | signal_name, start_pos, freq 278 | )); 279 | return Some(start_pos); 280 | } 281 | } else { 282 | println!("Window {}: No frequency detected", i); 283 | } 284 | 285 | if i % 10 == 0 { 286 | println!("Processed {} windows", i); 287 | } 288 | } 289 | 290 | spinner.finish_with_message(format!("No {} signal detected in current buffer", signal_name)); 291 | None 292 | } 293 | 294 | fn decode_audio(&mut self, samples: &[f32]) -> Vec { 295 | let samples_per_bit = (self.sample_rate as f64 * (BIT_DURATION_MS as f64 / 1000.0)) as usize; 296 | self.stats.total_samples = samples.len(); 297 | 298 | println!("\n{}", style("Decoding Parameters:").cyan()); 299 | println!("├─ Sample rate: {} Hz", self.sample_rate); 300 | println!("├─ Bit duration: {} ms", BIT_DURATION_MS); 301 | println!("├─ Samples per bit: {}", samples_per_bit); 302 | println!("├─ Zero frequency: {:.1} Hz", self.frequencies.zero); 303 | println!("└─ One frequency: {:.1} Hz", self.frequencies.one); 304 | 305 | let mut decoded = Vec::new(); 306 | let mut state = DecodeState::WaitingForSync; 307 | let mut sync_count = 0; 308 | let mut preamble_bits = 0; 309 | let mut expected_preamble = true; // true for 1, false for 0 310 | 311 | println!("\n{}", style("Starting decode process:").cyan()); 312 | 313 | for (i, chunk) in samples.chunks(samples_per_bit).enumerate() { 314 | if let Some(freq) = self.detect_frequency(chunk, i) { 315 | // println!("Chunk {}: {:.1} Hz", i, freq); 316 | 317 | match state { 318 | DecodeState::WaitingForSync => { 319 | if (freq - self.frequencies.start).abs() < FREQUENCY_TOLERANCE { 320 | sync_count += 1; 321 | println!("Sync marker {} detected", sync_count); 322 | if sync_count >= 4 { 323 | println!("{}", style("Sync sequence complete").green()); 324 | state = DecodeState::WaitingForPreamble; 325 | } 326 | } else { 327 | if sync_count > 0 { 328 | println!("Reset sync count (got {:.1} Hz)", freq); 329 | } 330 | sync_count = 0; 331 | } 332 | }, 333 | DecodeState::WaitingForPreamble => { 334 | let is_one = (freq - self.frequencies.one).abs() < FREQUENCY_TOLERANCE; 335 | let is_zero = (freq - self.frequencies.zero).abs() < FREQUENCY_TOLERANCE; 336 | 337 | if (is_one && expected_preamble) || (is_zero && !expected_preamble) { 338 | preamble_bits += 1; 339 | println!("Valid preamble bit {} of 16", preamble_bits); 340 | expected_preamble = !expected_preamble; 341 | if preamble_bits >= 16 { 342 | println!("{}", style("Preamble detected").green()); 343 | state = DecodeState::WaitingForByteStart; 344 | } 345 | } else { 346 | println!("Invalid preamble bit"); 347 | preamble_bits = 0; 348 | expected_preamble = true; 349 | } 350 | }, 351 | DecodeState::WaitingForByteStart => { 352 | if (freq - self.frequencies.one).abs() < FREQUENCY_TOLERANCE { 353 | state = DecodeState::ReadingBits { 354 | current_byte: 0, 355 | bits_read: 0 356 | }; 357 | println!("Starting new byte"); 358 | } 359 | }, 360 | DecodeState::ReadingBits { mut current_byte, bits_read } => { 361 | let bit = if (freq - self.frequencies.one).abs() < FREQUENCY_TOLERANCE { 1 } else { 0 }; 362 | current_byte = (current_byte << 1) | bit; 363 | 364 | // println!("Read bit {} ({}/8)", bit, bits_read + 1); 365 | 366 | if bits_read == 7 { 367 | state = DecodeState::WaitingForByteEnd; 368 | decoded.push(current_byte); 369 | if current_byte.is_ascii() { 370 | println!("Completed byte: 0x{:02x} (ASCII: {})", 371 | current_byte, 372 | if current_byte.is_ascii_control() { '.' } 373 | else { current_byte as char }); 374 | } else { 375 | println!("Completed byte: 0x{:02x}", current_byte); 376 | } 377 | } else { 378 | state = DecodeState::ReadingBits { 379 | current_byte, 380 | bits_read: bits_read + 1 381 | }; 382 | } 383 | }, 384 | DecodeState::WaitingForByteEnd => { 385 | if (freq - self.frequencies.zero).abs() < FREQUENCY_TOLERANCE { 386 | state = DecodeState::WaitingForByteStart; 387 | } else { 388 | println!("Warning: Missing byte end marker"); 389 | // Continue anyway 390 | state = DecodeState::WaitingForByteStart; 391 | } 392 | } 393 | } 394 | 395 | // Check for end marker 396 | if (freq - self.frequencies.end).abs() < FREQUENCY_TOLERANCE { 397 | println!("{}", style("End marker detected").green()); 398 | break; 399 | } 400 | } 401 | } 402 | 403 | println!("\n{}", style("Decode Summary:").cyan()); 404 | println!("├─ Decoded {} bytes", decoded.len()); 405 | if !decoded.is_empty() { 406 | println!("└─ First byte: 0x{:02x}", decoded[0]); 407 | } 408 | 409 | decoded 410 | } 411 | } 412 | 413 | 414 | struct FileReceiver { 415 | decoder: AudioDecoder, 416 | output_dir: PathBuf, 417 | } 418 | 419 | impl FileReceiver { 420 | 421 | fn new(output_dir: PathBuf) -> Self { 422 | // Create output directory if it doesn't exist 423 | std::fs::create_dir_all(&output_dir).expect("Failed to create output directory"); 424 | 425 | Self { 426 | decoder: AudioDecoder::new(SAMPLE_RATE), 427 | output_dir, 428 | } 429 | } 430 | 431 | fn debug_decoded_data(&self, data: &[u8]) { 432 | println!("\n{}", style("Decoded Data Analysis:").cyan().bold()); 433 | println!("├─ Total bytes: {}", data.len()); 434 | 435 | println!("├─ Pipe character (|) positions:"); 436 | for (i, &byte) in data.iter().enumerate() { 437 | if byte == b'|' { 438 | println!("│ ├─ Position {}", i); 439 | } 440 | } 441 | 442 | println!("└─ First 100 bytes:"); 443 | for chunk in data.iter().take(100).collect::>().chunks(16) { 444 | print!(" "); 445 | for byte in chunk { 446 | print!("{:02x} ", byte); 447 | } 448 | 449 | for _ in chunk.len()..16 { 450 | print!(" "); 451 | } 452 | 453 | print!(" "); 454 | for &byte in chunk { 455 | if byte.is_ascii_graphic() || *byte == b' ' { 456 | print!("{}", *byte as char); 457 | } else { 458 | print!("."); 459 | } 460 | } 461 | println!(); 462 | } 463 | } 464 | 465 | fn parse_header(&self, header_data: &[u8]) -> Result<(String, u64, String)> { 466 | let header_str = std::str::from_utf8(header_data) 467 | .context("Failed to parse header as UTF-8")?; 468 | 469 | println!("Raw header: {}", header_str); 470 | 471 | let parts: Vec<&str> = header_str.split('|').collect(); 472 | if parts.len() < 3 { 473 | anyhow::bail!("Invalid header format: expected 3 parts, got {}", parts.len()); 474 | } 475 | 476 | let filename = parts[0].to_string(); 477 | let size = parts[1].parse().context("Failed to parse file size")?; 478 | let checksum = parts[2].to_string(); 479 | 480 | Ok((filename, size, checksum)) 481 | } 482 | 483 | fn verify_checksum(&self, data: &[u8], expected: &str) -> bool { 484 | let mut hasher = Sha256::new(); 485 | hasher.update(data); 486 | let actual = hex::encode(hasher.finalize()); 487 | 488 | println!("Checksum verification:"); 489 | println!("├─ Expected: {}", style(expected).yellow()); 490 | println!("└─ Actual : {}", style(&actual).green()); 491 | 492 | actual == expected 493 | } 494 | 495 | fn start_receiving(&mut self) -> Result<()> { 496 | println!("{}", style("Audio File Receiver").cyan().bold()); 497 | 498 | let host = cpal::default_host(); 499 | 500 | let device = host.input_devices()? 501 | .find(|device| { 502 | let name = device.name().ok().unwrap_or_default(); 503 | name.to_lowercase().contains("blackhole") 504 | }) 505 | .context("Could not find BlackHole audio device")?; 506 | 507 | println!("Using audio input device: {}", style(device.name()?).green()); 508 | 509 | let config = device.default_input_config()?; 510 | println!("Device config: {:?}", config); 511 | 512 | let channels = config.channels() as usize; 513 | println!("Number of channels: {}", channels); 514 | 515 | let sample_counter = Arc::new(AtomicUsize::new(0)); 516 | let sample_counter_clone = sample_counter.clone(); 517 | 518 | let _running = Arc::new(AtomicBool::new(true)); 519 | let rb = HeapRb::::new(SAMPLE_RATE as usize * 60 * 2 * channels); 520 | let (mut producer, mut consumer) = rb.split(); 521 | 522 | let stream = device.build_input_stream( 523 | &config.into(), 524 | move |data: &[f32], _: &_| { 525 | if sample_counter_clone.load(std::sync::atomic::Ordering::Relaxed) % (SAMPLE_RATE as usize * 5) == 0 { 526 | let max_amp = data.iter().map(|&x| x.abs()).fold(0.0f32, f32::max); 527 | println!("Max amplitude in current buffer: {:.6}", max_amp); 528 | } 529 | 530 | let mono_samples: Vec = data.iter() 531 | .step_by(channels) 532 | .copied() 533 | .collect(); 534 | 535 | for &sample in &mono_samples { 536 | if producer.push(sample).is_err() { 537 | break; 538 | } 539 | } 540 | 541 | sample_counter_clone.fetch_add(data.len(), std::sync::atomic::Ordering::Relaxed); 542 | }, 543 | move |err| eprintln!("Error in audio stream: {}", err), 544 | None, 545 | )?; 546 | 547 | stream.play()?; 548 | println!("\n{}", style("Ready to receive transmission").yellow()); 549 | println!("Listening for sync tone... (Press Ctrl+C to exit)"); 550 | 551 | let mut all_samples = Vec::new(); 552 | let mut last_debug_time = Instant::now(); 553 | 554 | loop { 555 | std::thread::sleep(std::time::Duration::from_millis(100)); 556 | 557 | let mut new_samples = Vec::new(); 558 | while let Some(sample) = consumer.pop() { 559 | new_samples.push(sample); 560 | } 561 | 562 | if !new_samples.is_empty() && last_debug_time.elapsed() >= std::time::Duration::from_secs(1) { 563 | let max_amp = new_samples.iter().map(|&x| x.abs()).fold(0.0f32, f32::max); 564 | let rms = (new_samples.iter().map(|&x| x * x).sum::() / new_samples.len() as f32).sqrt(); 565 | println!("Buffer stats: {} samples, max amp: {:.6}, RMS: {:.6}", 566 | new_samples.len(), max_amp, rms); 567 | last_debug_time = Instant::now(); 568 | } 569 | 570 | all_samples.extend(new_samples); 571 | 572 | if all_samples.len() >= SAMPLE_RATE as usize * 3 { 573 | let rms = (all_samples.iter().map(|&x| x * x).sum::() / all_samples.len() as f32).sqrt(); 574 | println!("Full buffer stats before sync detection:"); 575 | println!("├─ Samples: {}", all_samples.len()); 576 | println!("└─ RMS amplitude: {:.6}", rms); 577 | 578 | if let Some(sync_pos) = self.decoder.wait_for_sync(&all_samples) { 579 | println!("\n{}", style("Sync detected! Waiting for preamble...").green()); 580 | 581 | // Keep collecting samples for a short while to ensure we have the preamble 582 | let mut samples_after_sync = all_samples[sync_pos..].to_vec(); 583 | let start_time = Instant::now(); 584 | 585 | while start_time.elapsed() < Duration::from_secs(2) { 586 | while let Some(sample) = consumer.pop() { 587 | samples_after_sync.push(sample); 588 | } 589 | thread::sleep(Duration::from_millis(100)); 590 | } 591 | 592 | if let Some(preamble_end) = self.decoder.wait_for_preamble(&samples_after_sync, 0) { 593 | all_samples = samples_after_sync[preamble_end..].to_vec(); 594 | println!("\n{}", style("Preamble detected! Receiving file...").green()); 595 | 596 | let start_time = Instant::now(); 597 | while start_time.elapsed() < Duration::from_secs(1000) { 598 | while let Some(sample) = consumer.pop() { 599 | all_samples.push(sample); 600 | } 601 | std::thread::sleep(Duration::from_millis(30)); 602 | } 603 | 604 | println!("\nRecording complete:"); 605 | println!("Captured {} samples ({:.2} seconds)", 606 | all_samples.len(), 607 | all_samples.len() as f32 / SAMPLE_RATE as f32); 608 | 609 | let decoded_data = self.decoder.decode_audio(&all_samples); 610 | 611 | if decoded_data.is_empty() { 612 | anyhow::bail!("No data decoded from audio signal"); 613 | } 614 | 615 | println!("\n{}", style("Looking for header in decoded data...").yellow()); 616 | self.debug_decoded_data(&decoded_data); 617 | 618 | if let Some(first_pipe) = decoded_data.iter().position(|&b| b == b'|') { 619 | if let Some(second_pipe_offset) = decoded_data[first_pipe + 1..].iter().position(|&b| b == b'|') { 620 | let second_pipe = first_pipe + 1 + second_pipe_offset; 621 | println!("\nFound header structure:"); 622 | println!("├─ First pipe at: {}", first_pipe); 623 | println!("└─ Second pipe at: {}", second_pipe); 624 | 625 | // Search for |END| marker in the entire decoded data 626 | if let Some(header_end) = decoded_data.windows(5) 627 | .enumerate() 628 | .find(|(_, window)| window == b"|END|") 629 | .map(|(pos, _)| pos) 630 | { 631 | println!("Found |END| marker at position {}", header_end); 632 | 633 | // Verify the header structure makes sense 634 | if header_end > second_pipe { 635 | let header_slice = &decoded_data[..header_end]; 636 | println!("Found header of {} bytes", header_slice.len()); 637 | println!("Header content: {:?}", std::str::from_utf8(header_slice).unwrap_or("Invalid UTF-8")); 638 | 639 | if let Ok((filename, size, checksum)) = self.parse_header(header_slice) { 640 | println!("\nHeader details:"); 641 | println!("├─ Filename: {}", style(&filename).green()); 642 | println!("├─ Size: {} bytes", style(size).green()); 643 | println!("└─ Checksum: {}", style(&checksum).green()); 644 | 645 | // Skip the header and the |END| marker 646 | let file_data = &decoded_data[header_end + 5..]; 647 | if file_data.len() < size as usize { 648 | println!("Warning: Not enough data after header ({} < {} bytes)", 649 | file_data.len(), size); 650 | return Err(anyhow::anyhow!("Incomplete file data")); 651 | } 652 | 653 | let file_data = &file_data[..size as usize]; 654 | 655 | if self.verify_checksum(file_data, &checksum) { 656 | let output_path = self.output_dir.join(&filename); 657 | 658 | // Create parent directories if they don't exist 659 | if let Some(parent) = output_path.parent() { 660 | std::fs::create_dir_all(parent) 661 | .context("Failed to create parent directories")?; 662 | } 663 | 664 | // Write the file 665 | std::fs::write(&output_path, file_data) 666 | .with_context(|| format!("Failed to write file to {}", output_path.display()))?; 667 | 668 | println!("\n{}", style("File successfully saved!").green().bold()); 669 | println!("Location: {}", style(output_path.display()).green()); 670 | self.decoder.stats.print_summary(); 671 | return Ok(()); 672 | } else { 673 | println!("{}", style("Checksum verification failed").red()); 674 | } 675 | } else { 676 | return Err(anyhow::anyhow!("Failed to parse header")); 677 | } 678 | } else { 679 | return Err(anyhow::anyhow!("Invalid header structure: END marker before second pipe")); 680 | } 681 | } else { 682 | return Err(anyhow::anyhow!("Could not find |END| marker")); 683 | } 684 | } else { 685 | return Err(anyhow::anyhow!("Could not find second pipe character")); 686 | } 687 | } else { 688 | return Err(anyhow::anyhow!("Could not find first pipe character")); 689 | } 690 | } 691 | } 692 | 693 | // If sync not found, keep only the last 2 seconds of samples 694 | let keep_samples = SAMPLE_RATE as usize * 2; 695 | if all_samples.len() > keep_samples { 696 | all_samples = all_samples[all_samples.len() - keep_samples..].to_vec(); 697 | } 698 | } 699 | } 700 | } 701 | } 702 | 703 | fn main() -> Result<()> { 704 | let args = Args::parse(); 705 | let mut receiver = FileReceiver::new(args.output_dir); 706 | 707 | println!("{}", style("Starting file receiver...").cyan().bold()); 708 | receiver.start_receiving()?; 709 | 710 | Ok(()) 711 | } 712 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------