Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 62 additions & 11 deletions cmping.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
"""

import argparse
import ipaddress
import os
import queue
import random
import signal
import string
import threading
import time
import urllib.parse
from statistics import stdev

from deltachat_rpc_client import DeltaChat, EventType, Rpc
Expand All @@ -23,13 +25,13 @@ def main():
parser.add_argument(
"relay1",
action="store",
help="chatmail relay domain",
help="chatmail relay domain or IP address",
)
parser.add_argument(
"relay2",
action="store",
nargs="?",
help="chatmail relay domain (defaults to relay1 if not specified)",
help="chatmail relay domain or IP address (defaults to relay1 if not specified)",
)
parser.add_argument(
"-c",
Expand Down Expand Up @@ -79,16 +81,65 @@ def _add_online(self, account):
account.start_io()
self.online.append(account)

def get_relay_account(self, domain):
for account in self.dc.get_all_accounts():
addr = account.get_config("configured_addr")
if addr is not None and addr.split("@")[1] == domain:
if account not in self.online:
break
else:
print(f"# creating account on {domain}")
def _is_ip_address(self, host):
"""Check if host is an IP address."""
try:
ipaddress.ip_address(host)
return True
except ValueError:
return False

def _generate_username(self):
"""Generate a 12-character alphanumeric lowercase username."""
ALPHANUMERIC = string.ascii_lowercase + string.digits
return "".join(random.choices(ALPHANUMERIC, k=12))

def _generate_password(self):
"""Generate a 30-character alphanumeric password."""
ALPHANUMERIC = string.ascii_letters + string.digits
return "".join(random.choices(ALPHANUMERIC, k=30))

def get_relay_account(self, domain_or_ip):
# Check if this is an IP address
is_ip = self._is_ip_address(domain_or_ip)

if is_ip:
# For IP addresses, check if we already have an account for this IP
# (check the host part of the configured address)
for account in self.dc.get_all_accounts():
addr = account.get_config("configured_addr")
if addr is not None:
host_part = addr.split("@")[1] if "@" in addr else None
if host_part == domain_or_ip:
if account not in self.online:
self._add_online(account)
return account

# Create new account with dclogin scheme
username = self._generate_username()
password = self._generate_password()
print(f"# creating account on {domain_or_ip} with username {username}")
account = self.dc.add_account()
account.set_config_from_qr(f"dcaccount:{domain}")

# Build dclogin URL with IP address
# Format: dclogin:username@ip/?p=password&v=1&ip=993&sp=465&ic=3&ss=default
IMAP_PORT = "993"
SMTP_PORT = "465"
CERT_CHECKS = "3"
SMTP_SECURITY = "default"
qr_url = f"dclogin:{username}@{domain_or_ip}/?p={urllib.parse.quote(password)}&v=1&ip={IMAP_PORT}&sp={SMTP_PORT}&ic={CERT_CHECKS}&ss={SMTP_SECURITY}"
account.set_config_from_qr(qr_url)
else:
# Original domain-based logic
for account in self.dc.get_all_accounts():
addr = account.get_config("configured_addr")
if addr is not None and addr.split("@")[1] == domain_or_ip:
if account not in self.online:
break
else:
print(f"# creating account on {domain_or_ip}")
account = self.dc.add_account()
account.set_config_from_qr(f"dcaccount:{domain_or_ip}")

self._add_online(account)
return account
Expand Down