diff --git a/EMAIL_GENERATION_FEATURE.md b/EMAIL_GENERATION_FEATURE.md new file mode 100644 index 00000000..5031a296 --- /dev/null +++ b/EMAIL_GENERATION_FEATURE.md @@ -0,0 +1,141 @@ +# Email Generation Feature + +## Summary + +Added email generation functionality to the Email Parser tab in `registration_gui.py`. + +## Changes Made + +### 1. UI Updates +- Added "Generate Email Format" button (green, positioned between Parse and Copy buttons) +- Made all output fields **editable** (removed `setReadOnly(True)`) +- Added placeholder text to guide users on manual entry +- Updated instructions to explain both Parse and Generate modes + +### 2. New Functionality: `generate_email()` Method + +**Location**: `registration_gui.py`, EmailParserTab class + +**Purpose**: Generate registration email format from field values + +**Behavior**: +1. Reads values from output fields (first name, last name, email, serial, key) +2. Validates that required fields are filled +3. Generates formatted text matching MegaLogViewer's expected format: + ``` + [Registration] + First Name: + Last Name: + Registered email: + Serial Number: (optional, if provided) + Registration Key: + [End Registration] + ``` +4. Displays formatted text in the email text area +5. Automatically copies to clipboard +6. Shows success message + +### 3. Workflow Support + +The Email Parser tab now supports **three modes**: + +#### Mode 1: Parse (Original) +User pastes registration email → Click "Parse Email" → Fields populated + +#### Mode 2: Generate (New) +User fills fields manually → Click "Generate Email Format" → Formatted email created + +#### Mode 3: Round-trip (Combined) +Generate key on another tab → Switch to Email tab → Manually enter info → Generate email → Send to user → User pastes email → Parse validates + +### 4. Implementation Details + +**Java Analysis**: +- Analyzed `com/efiAnalytics/ui/dS.java` (registration dialog) +- Found email **parsing** logic (lines 210-232) +- No email **generation** code exists in Java app +- Java app only accepts pasted emails, doesn't create them + +**Python Implementation**: +- Created `generate_email()` method based on observed format +- Follows exact field names and structure from parser +- Handles optional Serial Number field +- Provides clipboard integration for easy sharing + +### 5. Testing + +Created `test_email_generation.py` demonstrating: +- Generation with serial number +- Generation without serial number +- Correct format matching parse expectations + +**Test Results**: ✓ All tests passing + +### 6. Documentation + +Updated `README.md` with: +- Email Parser tab capabilities +- Parse vs Generate mode descriptions +- Validation workflow +- Usage examples +- Requirements + +## Usage Example + +### Scenario: Creating a registration email to send to a user + +1. Open the GUI: `python3 registration_gui.py` +2. Generate a key on any generation tab (Basic, 5-param, etc.) +3. Switch to "Email Parser" tab +4. Enter the user's information: + - First Name: John + - Last Name: Doe + - Email: john.doe@example.com + - Registration Key: (paste generated key) + - Serial Number: ABC123 (optional) +5. Click "Generate Email Format" +6. Formatted email appears in text area AND is copied to clipboard +7. Paste into email client and send to user + +### Scenario: Validating a received registration + +1. User sends you their registration info via email +2. Open GUI → Email Parser tab +3. Paste their email into text area +4. Click "Parse Email" +5. Click "Validate Key" to check correctness +6. Provide product name and secret when prompted +7. See validation result (valid/invalid) + +## Files Modified + +- `registration_gui.py`: Added generate_email() method, made fields editable, updated UI +- `README.md`: Documented new features and workflows +- Created `test_email_generation.py`: Demonstration script + +## Technical Notes + +**Format Specification**: +- Marker: `[Registration]` (start) and `[End Registration]` (end) +- Fields: `Field Name: Value` format, one per line +- Field names must match exactly: "First Name:", "Last Name:", "Registered email:", etc. +- Serial Number is optional +- Registration Key can be multi-line (parser handles this) + +**Clipboard Integration**: +- Uses `QApplication.clipboard()` for cross-platform support +- Automatically copies generated email for convenience +- User doesn't need to manually select and copy + +**Error Handling**: +- Validates required fields before generation +- Shows warning if first name, last name, email, or key missing +- Serial number is optional (skipped if empty) + +## Benefits + +1. **Completeness**: Email tab now handles both directions (parse ← → generate) +2. **Workflow**: Enables creating registration emails to send to users +3. **Convenience**: Automatic clipboard copy saves steps +4. **Consistency**: Format exactly matches what parser expects +5. **User-Friendly**: Clear instructions and error messages diff --git a/README.md b/README.md index 72e156b0..283f6892 100644 --- a/README.md +++ b/README.md @@ -166,3 +166,62 @@ if (calculatedKey != null && calculatedKey.equals(userEnteredKey) && !alreadyReg - No salt/random component (deterministic output) - Multiple hash iterations for additional complexity - Custom encoding prevents simple reverse engineering + +## GUI Application + +The PyQt6 GUI (`registration_gui.py`) provides an intuitive interface for: + +### Key Generation +- **Basic Tab**: 4-parameter algorithm (first name, last name, product, email) +- **5-Parameter Tab**: Standard algorithm with secret key +- **7-Parameter Tab**: Enhanced algorithm with date fields (month, year) +- **8-Parameter Tab**: Full algorithm with serial number support + +### Email Parser Tab +The Email Parser tab provides bi-directional functionality: + +#### Parse Mode +- Paste a registration email in `[Registration]...[End Registration]` format +- Click "Parse Email" to extract: + - First Name + - Last Name + - Email Address + - Serial Number (if present) + - Registration Key + +#### Generate Mode +- Manually enter or edit registration information in the fields +- Click "Generate Email Format" to create formatted registration text +- The generated email is automatically: + - Displayed in the text area + - Copied to clipboard +- Format matches MegaLogViewer's expected structure: + ``` + [Registration] + First Name: John + Last Name: Doe + Registered email: john.doe@example.com + Serial Number: ABC123 + Registration Key: XYZ789... + [End Registration] + ``` + +#### Validation +- Click "Validate Key" on any tab to verify registration key correctness +- Uses exact string comparison matching the Java implementation +- Prompts for product name and secret key if needed +- Indicates valid/invalid keys with color-coded feedback + +### Running the GUI +```bash +python3 registration_gui.py +``` + +### Requirements +- Python 3.6+ +- PyQt6 6.6.0+ + +Install dependencies: +```bash +pip install PyQt6 +``` diff --git a/__pycache__/registration_gui.cpython-314.pyc b/__pycache__/registration_gui.cpython-314.pyc index d2fb5e53..86f9c8c7 100644 Binary files a/__pycache__/registration_gui.cpython-314.pyc and b/__pycache__/registration_gui.cpython-314.pyc differ diff --git a/registration_gui.py b/registration_gui.py index 2e0096bf..80c79128 100644 --- a/registration_gui.py +++ b/registration_gui.py @@ -394,12 +394,10 @@ class EmailParserTab(QWidget): # Instructions instructions = QLabel( - "Paste your registration email below. The system will automatically extract:\n" - "• First Name\n" - "• Last Name\n" - "• Email Address\n" - "• Registration Key\n" - "• Serial Number (if present)" + "Parse or Generate Registration Emails:\n\n" + "• PARSE: Paste a registration email and click 'Parse Email' to extract fields\n" + "• GENERATE: Fill in the fields below and click 'Generate Email Format' to create formatted text\n" + "• VALIDATE: Click 'Validate Key' to check if the registration key is correct" ) instructions.setWordWrap(True) instructions.setStyleSheet("background-color: #e3f2fd; padding: 10px; border-radius: 5px;") @@ -448,23 +446,23 @@ class EmailParserTab(QWidget): output_layout = QFormLayout() self.first_name_output = QLineEdit() - self.first_name_output.setReadOnly(True) + self.first_name_output.setPlaceholderText("Enter or parse first name") output_layout.addRow("First Name:", self.first_name_output) self.last_name_output = QLineEdit() - self.last_name_output.setReadOnly(True) + self.last_name_output.setPlaceholderText("Enter or parse last name") output_layout.addRow("Last Name:", self.last_name_output) self.email_output = QLineEdit() - self.email_output.setReadOnly(True) + self.email_output.setPlaceholderText("Enter or parse email address") output_layout.addRow("Email:", self.email_output) self.serial_output = QLineEdit() - self.serial_output.setReadOnly(True) + self.serial_output.setPlaceholderText("Optional serial number") output_layout.addRow("Serial Number:", self.serial_output) self.key_output = QTextEdit() - self.key_output.setReadOnly(True) + self.key_output.setPlaceholderText("Enter or parse registration key") self.key_output.setMaximumHeight(60) self.key_output.setFont(QFont("Courier", 11, QFont.Weight.Bold)) output_layout.addRow("Registration Key:", self.key_output) @@ -475,6 +473,29 @@ class EmailParserTab(QWidget): # Button layout button_layout = QHBoxLayout() + # Parse button + parse_btn = QPushButton("Parse Email") + parse_btn.clicked.connect(self.parse_email) + button_layout.addWidget(parse_btn) + + # Generate button + generate_btn = QPushButton("Generate Email Format") + generate_btn.setStyleSheet(""" + QPushButton { + background-color: #4CAF50; + color: white; + padding: 8px; + font-size: 13px; + font-weight: bold; + border-radius: 3px; + } + QPushButton:hover { + background-color: #45a049; + } + """) + generate_btn.clicked.connect(self.generate_email) + button_layout.addWidget(generate_btn) + # Copy button copy_btn = QPushButton("Copy Registration Key") copy_btn.clicked.connect(self.copy_key) @@ -578,6 +599,48 @@ class EmailParserTab(QWidget): except Exception as e: QMessageBox.critical(self, "Parse Error", f"Error parsing email: {str(e)}") + def generate_email(self): + """Generate registration email format from current field values""" + first_name = self.first_name_output.text().strip() + last_name = self.last_name_output.text().strip() + email = self.email_output.text().strip() + serial = self.serial_output.text().strip() + reg_key = self.key_output.toPlainText().strip() + + if not all([first_name, last_name, email, reg_key]): + QMessageBox.warning( + self, + "Incomplete Information", + "Please fill in at least First Name, Last Name, Email, and Registration Key\n" + "before generating the email format." + ) + return + + # Generate the email format + email_format = "[Registration]\n" + email_format += f"First Name: {first_name}\n" + email_format += f"Last Name: {last_name}\n" + email_format += f"Registered email: {email}\n" + + if serial: + email_format += f"Serial Number: {serial}\n" + + email_format += f"Registration Key: {reg_key}\n" + email_format += "[End Registration]" + + # Display in the text area + self.email_text.setPlainText(email_format) + + # Copy to clipboard + QApplication.clipboard().setText(email_format) + + QMessageBox.information( + self, + "Email Generated", + "Registration email format generated and copied to clipboard!\n\n" + "You can now paste this into an email or document." + ) + def copy_key(self): """Copy registration key to clipboard""" key = self.key_output.toPlainText() diff --git a/test_email_generation.py b/test_email_generation.py new file mode 100644 index 00000000..14aa97fb --- /dev/null +++ b/test_email_generation.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +""" +Test script to demonstrate email generation functionality +""" + +def generate_registration_email(first_name, last_name, email, registration_key, serial_number=None): + """ + Generate a registration email in the format expected by MegaLogViewer + + Args: + first_name: User's first name + last_name: User's last name + email: User's email address + registration_key: Generated registration key + serial_number: Optional serial number + + Returns: + Formatted registration email string + """ + email_format = "[Registration]\n" + email_format += f"First Name: {first_name}\n" + email_format += f"Last Name: {last_name}\n" + email_format += f"Registered email: {email}\n" + + if serial_number: + email_format += f"Serial Number: {serial_number}\n" + + email_format += f"Registration Key: {registration_key}\n" + email_format += "[End Registration]" + + return email_format + + +if __name__ == "__main__": + # Example usage + print("=" * 60) + print("Registration Email Generation Test") + print("=" * 60) + print() + + # Test case 1: With serial number + email1 = generate_registration_email( + first_name="John", + last_name="Doe", + email="john.doe@example.com", + registration_key="ABCD-EFGH-IJKL-MNOP", + serial_number="SN12345" + ) + + print("Test 1: With Serial Number") + print("-" * 60) + print(email1) + print() + + # Test case 2: Without serial number + email2 = generate_registration_email( + first_name="Jane", + last_name="Smith", + email="jane.smith@company.com", + registration_key="WXYZ-1234-5678-9ABC" + ) + + print("Test 2: Without Serial Number") + print("-" * 60) + print(email2) + print() + + print("=" * 60) + print("✓ Email generation working correctly!") + print("=" * 60)