commit 499c02b202ae2e83c3c0178209545fab9b4d0e6c Author: Lúcio Carvalho Almeida Date: Fri Dec 19 18:46:06 2025 -0300 setup funcional diff --git a/README.md b/README.md new file mode 100644 index 0000000..013803a --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# Microw + +**Microw** é um utilitário de linha de comando (CLI) desenvolvido em Python para automatizar a conversão de dados tabulares (como arquivos CSV ou TXT) em arquivos de configuração `.ini` compatíveis com o softphone **MicroSIP** e seus derivados. + +Esta ferramenta é ideal para administradores de sistemas VoIP, suporte técnico e desenvolvedores que precisam realizar o provisionamento em massa de ramais de forma rápida e precisa. + +## Funcionalidades + +* **Mapeamento Flexível:** Define a ordem das colunas do seu arquivo de entrada via linha de comando. +* **Templates Customizáveis:** Permite o uso de modelos de conta personalizados para diferentes cenários de rede. +* **Padrões de Label:** Gere nomes de exibição (DisplayName) dinâmicos baseados nos dados de entrada. +* **Conta Ghost:** Opção para adicionar um perfil "Desconectado" como primeira conta da lista. +* **Suporte a Delimitadores:** Funciona com vírgulas, tabs (`\t`), pontos e vírgulas, etc. + +## Como Usar + +### Pré-requisitos + +* Python 3.x instalado. + +### Instalação + +Basta clonar o repositório ou baixar o arquivo `microw.py`: + +```bash +git clone https://github.com/LucioCarvalhoDev/microw.git +cd microw +``` + +### Execução Básica + +Supondo que você tenha um arquivo `seus_dados.csv` com o formato `ramal,label`: + +```bash +python3 microw.py --input seus_dados.csv --output accounts.ini +``` + +--- + +## Referência de Argumentos + +| Argumento | Padrão | Descrição | +| --- | --- | --- | +| `--format` | `"ramal label"` | Ordem das colunas (use `_` para ignorar colunas). | +| `--input` | `./input.txt` | Caminho do arquivo de origem. | +| `--output` | `./output.ini` | Caminho do arquivo `.ini` gerado. | +| `--delimiter` | `,` | Caractere separador de colunas. | +| `--label-pattern` | `label` | Template para o nome de exibição (ex: `"ramal - label"`). | +| `--add-ghost` | `False` | Adiciona conta de 'Desconectado' no topo. | +| `--set-template` | `None` | Caminho para um arquivo de template de conta customizado. | + +--- + +## Exemplos de Uso + +### 1. Formato CSV com Ponto e Vírgula + +Se o seu arquivo segue o padrão `ID;Ramal;Nome;Setor` e você quer ignorar o ID: + +```bash +python3 microw.py --delimiter ";" --format "_ ramal label setor" + +``` + +### 2. Customizando o Nome de Exibição + +Para que no MicroSIP o nome apareça como `Ramal | Nome (Setor)`: + +```bash +python3 microw.py --format "ramal label setor" --label-pattern "ramal | label (setor)" + +``` + +### 3. Usando um Template de Conta Específico + +Se você precisa de configurações de transporte (TLS/TCP) ou portas diferentes, crie um arquivo de template e aponte-o: + +```bash +python3 microw.py --set-template meu_modelo.txt --input ramais.txt + +``` + +--- + +## Licença e Créditos + +Desenvolvido por **Lúcio Carvalho Almeida**. + +Este projeto é **Software Livre** (Open Source). + +**Contato:** [luciocarvalhodev@gmail.com](mailto:luciocarvalhodev@gmail.com) + +--- + +Sinta-se à vontade para contribuir com Pull Requests! + +--- diff --git a/microw.py b/microw.py new file mode 100644 index 0000000..4a3f9b4 --- /dev/null +++ b/microw.py @@ -0,0 +1,242 @@ +import sys +from enum import Enum +from pathlib import Path +import codecs + +MAN = """ +NOME + microw - convert data to MicroSIP accounts + +USO + python3 microw.py [OPÇÔES] + +DESCRIÇÂO + Utilitário para conversão de dados tabulares (CSV, TXT) em arquivos de + configuração (.ini) para o softphone MicroSIP e variantes. + + Feito por Lúcio Carvalho Almeida, Free Software. + +ARGUMENTOS + --format Define a ordem das colunas no arquivo de entrada. + Use nomes de variáveis (ex: ramal, password) ou + '_' para ignorar uma coluna específica. + Padrão: "ramal label" + Variáveis especiais: 'name', 'label', 'password', + 'server' + + --input Caminho do arquivo de origem dos dados. + Padrão: "./input.txt" + + --output Caminho onde o arquivo .ini será gerado. + Padrão: "./output.ini" + + --delimiter Caractere separador de colunas (aceita '\\t', ' '). + Padrão: "," + + --label-pattern Template para customizar o nome de exibição. + Substitui nomes de variáveis pelos seus valores. + Ex: "ramal - label (setor)" + + --add-ghost Se presente, adiciona uma conta de 'Desconectado' + como o primeiro perfil da lista. + + --set-template Fornece o caminho para o arquivo que será + usado no lugar de ACCOUNT_TEMPLATE + + --read-encoding Define a codificação de leitura + +EXEMPLOS + 1. Formato padrão com separador de ponto e vírgula: + python3 microw.py --delimiter ";" + + 2. Ignorando a 1ª coluna e formatando o nome de exibição: + python3 microw.py --format "_ ramal label setor" --label-pattern "label [setor]" + + 3. Usando um arquivo específico e adicionando conta fantasma: + python3 microw.py --input lista_vendas.csv --add-ghost + +CREDITOS + Desenvolvido por Lúcio Carvalho Almeida, Open Source. + Contato em luciocarvalhodev@gmail.com. +""" + +ACCOUNT_TEMPLATE = r''' +[Account_] +label=$label +server=$server +proxy=$server +domain=$server +username=$ramal +password=$password +authID=$ramal +displayName= +dialingPrefix= +dialPlan= +hideCID=0 +voicemailNumber= +transport=udp +publicAddr= +SRTP= +registerRefresh=300 +keepAlive=15 +publish=0 +ICE=0 +allowRewrite=0 +disableSessionTimer=0 +''' + +GHOST_TEMPLATE = r''' +[Account_] +label=Desconectado +server=0.0.0.0 +proxy=0.0.0.0 +domain=0.0.0.0 +username=0000 +password=1234 +authID=0000 +''' + +class SchemaValue(Enum): + Argument = 1 + Bool = 2 + +class Config: + def __init__(self): + self.config = { + "format": { + "default": "ramal label", + "schema": SchemaValue.Argument, + "value": None + }, + "input": { + "default": "./input.txt", + "schema": SchemaValue.Argument, + "value": None + }, + "add-ghost": { + "default": False, + "schema": SchemaValue.Bool, + "value": None + }, + "delimiter": { + "default": ",", + "schema": SchemaValue.Argument, + "value": None + }, + "output": { + "default": "./output.ini", + "schema": SchemaValue.Argument, + "value": None + }, + "label-pattern": { + "default": "label", + "schema": SchemaValue.Argument, + "value": None + }, + "help": { + "default": None, + "schema": SchemaValue.Bool, + "value": None + }, + "set-template": { + "default": None, + "schema": SchemaValue.Argument, + "value": None + } + } + + def _validate_setting(self, setting): + if not setting in self.config: + raise ValueError(f"'{setting}' is not a valid option.") + + def get(self, setting): + self._validate_setting(setting) + return self.config[setting]["value"] or self.config[setting]["default"] + + def set(self, setting, value): + self._validate_setting(setting) + self.config[setting]["value"] = value + + def schema(self, setting): + self._validate_setting(setting) + return self.config[setting]["schema"] + +config = Config() + +def main(): + # Faz o parse manual das flags e argumentos + args = sys.argv[1:] + while len(args): + argument = args.pop(0) + if argument[:2] == "--": + argument = argument[2:] + + if argument == "help": + print(MAN) + return + + if config.schema(argument) == SchemaValue.Argument: + config.set(argument, codecs.decode(args.pop(0), "unicode_escape")) + else: + config.set(argument, not config.get(argument)) + + output_file = Path(config.get("output")) + input_file = Path(config.get("input")) + input_lines = [line.strip() for line in input_file.open("r", encoding="utf-8").readlines()] + + accounts_settings = [] + format_vars = config.get("format").split(" ") + label_pattern = config.get("label-pattern") + + for line in input_lines: + if not line: continue + + data = [field.strip() for field in line.split(config.get("delimiter"))] + account_dict = {} + + # Mapeia os dados ignorando o caractere '_' + for i in range(min(len(data), len(format_vars))): + var_name = format_vars[i] + if var_name != "_": + account_dict[var_name] = data[i] + + # Customização do $label + if label_pattern: + pattern_parts = label_pattern.split(" ") + + # Se a parte for uma variável conhecida, substitui pelo valor + new_label = " ".join([account_dict.get(name, name) for name in pattern_parts]) + account_dict["label"] = new_label + + accounts_settings.append(account_dict) + + result = "" + + if config.get("add-ghost"): + result += GHOST_TEMPLATE + + current_account_template = ACCOUNT_TEMPLATE + + if not config.get("set-template") is None: + current_account_template = Path(config.get("set-template")).read_text(encoding="utf-8") + + for account in accounts_settings: + new_entry = current_account_template + # Substitui todas as variáveis encontradas + for var_name, value in account.items(): + new_entry = new_entry.replace("$" + var_name, str(value)) + + result += new_entry.strip() + "\n" + + result = result.strip() + + # Numeração sequencial das contas [Account1], [Account2]... + id = 1 + while "Account_" in result: + result = result.replace("Account_", f"Account{id}", 1) + id += 1 + + output_file.write_text(result, encoding="utf-8") + print(f"Sucesso: {id-1} contas criadas em '{output_file}'.") + +main() \ No newline at end of file