PHP Classes

File: scripts/generate_packet.php

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   scripts/generate_packet.php   Download  
File: scripts/generate_packet.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 6 days ago
Size: 8,990 bytes
 

Contents

Class file image Download
#!/usr/bin/env php
<?php
/**
 * Standalone FidoNet Packet Generator
 *
 * Creates FTS-0001 compatible .pkt files for testing.
 * Does not require database or application config.
 */

function showUsage() {
    echo
"FidoNet Packet Generator - Create test .pkt files\n";
    echo
"=================================================\n\n";
    echo
"Usage: php generate_packet.php [options]\n\n";
    echo
"Options:\n";
    echo
" --from-addr=ADDR Origin FTN address (required, e.g., 1:123/456)\n";
    echo
" --to-addr=ADDR Destination FTN address (required, e.g., 1:234/567)\n";
    echo
" --from-name=NAME Sender name (default: Test Sender)\n";
    echo
" --to-name=NAME Recipient name (default: Test Recipient)\n";
    echo
" --subject=SUBJ Message subject (default: Test Message)\n";
    echo
" --text=TEXT Message body text (default: test content)\n";
    echo
" --text-file=PATH Read message body from file\n";
    echo
" --echoarea=TAG Create echomail for this area (adds AREA: line)\n";
    echo
" --output=PATH Output file path (default: ./test_<timestamp>.pkt)\n";
    echo
" --help Show this help message\n\n";
    echo
"Examples:\n";
    echo
" # Simple netmail packet\n";
    echo
" php generate_packet.php --from-addr=1:123/456 --to-addr=1:234/567\n\n";
    echo
" # Netmail with custom content\n";
    echo
" php generate_packet.php --from-addr=1:123/456 --to-addr=1:234/567 \\\n";
    echo
" --from-name=\"John Doe\" --to-name=\"Jane Smith\" \\\n";
    echo
" --subject=\"Hello\" --text=\"This is a test message.\"\n\n";
    echo
" # Echomail packet\n";
    echo
" php generate_packet.php --from-addr=1:123/456 --to-addr=1:234/567 \\\n";
    echo
" --echoarea=GENERAL --subject=\"Test Post\"\n\n";
    echo
" # Read body from file\n";
    echo
" php generate_packet.php --from-addr=1:123/456 --to-addr=1:234/567 \\\n";
    echo
" --text-file=message.txt --output=outbound/test.pkt\n\n";
}

function
parseAddress($addr) {
   
// Parse FTN address: zone:net/node or zone:net/node.point
   
$addr = trim($addr);

   
// Handle zone:net/node.point format
   
if (preg_match('/^(\d+):(\d+)\/(\d+)(?:\.(\d+))?$/', $addr, $matches)) {
        return [
           
'zone' => (int)$matches[1],
           
'net' => (int)$matches[2],
           
'node' => (int)$matches[3],
           
'point' => isset($matches[4]) ? (int)$matches[4] : 0,
        ];
    }

    return
null;
}

function
writePacketHeader($handle, $origAddr, $destAddr) {
   
$now = time();

   
// Standard FTS-0001 58-byte packet header
   
$header = pack('vvvvvvvvvvvv',
       
$origAddr['node'], // 0-1: Origin node
       
$destAddr['node'], // 2-3: Destination node
       
(int)date('Y', $now), // 4-5: Year
       
(int)date('n', $now) - 1,// 6-7: Month (0-based)
       
(int)date('j', $now), // 8-9: Day
       
(int)date('G', $now), // 10-11: Hour
       
(int)date('i', $now), // 12-13: Minute
       
(int)date('s', $now), // 14-15: Second
       
0, // 16-17: Baud rate
       
2, // 18-19: Packet version (2)
       
$origAddr['net'], // 20-21: Origin net
       
$destAddr['net'] // 22-23: Destination net
   
);

   
// Product code low (8 bytes)
   
$header .= str_pad('', 8, "\0");

   
// Product code high (2 bytes)
   
$header .= str_pad('', 2, "\0");

   
// FSC-39 zone information (4 bytes)
   
$header .= pack('vv', $origAddr['zone'], $destAddr['zone']);

   
// Password (8 bytes)
   
$header .= str_pad('', 8, "\0");

   
// Reserved (6 bytes)
   
$header .= str_pad('', 6, "\0");

   
// FSC-48 zone info (4 bytes)
   
$header .= pack('vv', $origAddr['zone'], $destAddr['zone']);

   
// Auxiliary net (2 bytes)
   
$header .= str_pad('', 2, "\0");

    if (
strlen($header) !== 58) {
        throw new
Exception('Invalid packet header length: ' . strlen($header));
    }

   
fwrite($handle, $header);
}

function
writeMessage($handle, $origAddr, $destAddr, $fromName, $toName, $subject, $text, $echoarea = null) {
   
// Message type (2 = stored message)
   
fwrite($handle, pack('v', 2));

   
// Message attributes
   
$attrs = $echoarea ? 0x0000 : 0x0001; // 0x0001 = Private for netmail
   
fwrite($handle, pack('v', $attrs));

   
// Cost
   
fwrite($handle, pack('v', 0));

   
// Addresses in message header
   
fwrite($handle, pack('vvvv',
       
$origAddr['node'],
       
$destAddr['node'],
       
$origAddr['net'],
       
$destAddr['net']
    ));

   
// Date/time string (null-terminated, max 20 chars)
   
$dateStr = date('d M y H:i:s');
   
fwrite($handle, str_pad($dateStr, 20, "\0"));

   
// To name (null-terminated, max 36 chars)
   
fwrite($handle, substr($toName, 0, 35) . "\0");

   
// From name (null-terminated, max 36 chars)
   
fwrite($handle, substr($fromName, 0, 35) . "\0");

   
// Subject (null-terminated, max 72 chars)
   
fwrite($handle, substr($subject, 0, 71) . "\0");

   
// Message text with kludges
   
$fullText = '';

   
// Add AREA: line for echomail
   
if ($echoarea) {
       
$fullText .= "AREA:{$echoarea}\r"; // No space after AREA:
   
}

   
// Add standard kludges
   
$msgid = sprintf("%d:%d/%d.%d %08x",
       
$origAddr['zone'], $origAddr['net'], $origAddr['node'], $origAddr['point'],
       
time()
    );
   
$fullText .= "\x01MSGID: {$msgid}\r";
   
$fullText .= "\x01PID: PacketGenerator 1.0\r";
   
$fullText .= "\x01CHRS: UTF-8 4\r";
   
$fullText .= "\x01TZUTC: " . date('O') . "\r";

   
// Add message body
   
$fullText .= $text;

   
// Ensure proper line endings
   
$fullText = str_replace(["\r\n", "\n"], "\r", $fullText);

   
// Add tearline and origin for echomail
   
if ($echoarea) {
       
$fullText .= "\r--- PacketGenerator 1.0\r";
       
$fullText .= sprintf(" * Origin: Test System (%d:%d/%d)\r",
           
$origAddr['zone'], $origAddr['net'], $origAddr['node']
        );
    }

   
// Null-terminate message text
   
fwrite($handle, $fullText . "\0");
}

// Parse command line arguments
$options = [
   
'from-addr' => null,
   
'to-addr' => null,
   
'from-name' => 'Test Sender',
   
'to-name' => 'Test Recipient',
   
'subject' => 'Test Message',
   
'text' => "This is a test message generated by PacketGenerator.\r\rHave a nice day!",
   
'text-file' => null,
   
'echoarea' => null,
   
'output' => null,
   
'help' => false,
];

for (
$i = 1; $i < $argc; $i++) {
   
$arg = $argv[$i];

    if (
$arg === '--help' || $arg === '-h') {
       
$options['help'] = true;
    } elseif (
preg_match('/^--(\w+(?:-\w+)*)=(.*)$/', $arg, $matches)) {
       
$key = $matches[1];
       
$value = $matches[2];
        if (
array_key_exists($key, $options)) {
           
$options[$key] = $value;
        } else {
            echo
"Unknown option: --$key\n";
            exit(
1);
        }
    }
}

if (
$options['help']) {
   
showUsage();
    exit(
0);
}

// Validate required options
if (!$options['from-addr']) {
    echo
"Error: --from-addr is required\n\n";
   
showUsage();
    exit(
1);
}

if (!
$options['to-addr']) {
    echo
"Error: --to-addr is required\n\n";
   
showUsage();
    exit(
1);
}

// Parse addresses
$fromAddr = parseAddress($options['from-addr']);
if (!
$fromAddr) {
    echo
"Error: Invalid from address format. Use zone:net/node (e.g., 1:123/456)\n";
    exit(
1);
}

$toAddr = parseAddress($options['to-addr']);
if (!
$toAddr) {
    echo
"Error: Invalid to address format. Use zone:net/node (e.g., 1:123/456)\n";
    exit(
1);
}

// Read text from file if specified
if ($options['text-file']) {
    if (!
file_exists($options['text-file'])) {
        echo
"Error: Text file not found: {$options['text-file']}\n";
        exit(
1);
    }
   
$options['text'] = file_get_contents($options['text-file']);
}

// Determine output path
$outputPath = $options['output'] ?? './test_' . time() . '.pkt';

// Create the packet
echo "Creating packet...\n";
echo
" From: {$options['from-addr']} ({$options['from-name']})\n";
echo
" To: {$options['to-addr']} ({$options['to-name']})\n";
echo
" Subject: {$options['subject']}\n";
if (
$options['echoarea']) {
    echo
" Echoarea: {$options['echoarea']}\n";
}
echo
" Output: $outputPath\n";

try {
   
$handle = fopen($outputPath, 'wb');
    if (!
$handle) {
        throw new
Exception("Cannot create output file: $outputPath");
    }

   
// Write packet header
   
writePacketHeader($handle, $fromAddr, $toAddr);

   
// Write message
   
writeMessage($handle, $fromAddr, $toAddr,
       
$options['from-name'], $options['to-name'],
       
$options['subject'], $options['text'],
       
$options['echoarea']
    );

   
// Write packet terminator
   
fwrite($handle, pack('v', 0));

   
fclose($handle);

   
$size = filesize($outputPath);
    echo
"\nPacket created successfully!\n";
    echo
" File: $outputPath\n";
    echo
" Size: $size bytes\n";

} catch (
Exception $e) {
    echo
"Error: " . $e->getMessage() . "\n";
    exit(
1);
}