Ajuda com arquivo de senha perdido/ criptografia senha

Fórum sobre a linguagem CA-Clipper.

Moderador: Moderadores

Jefferson81br
Usuário Nível 1
Usuário Nível 1
Mensagens: 3
Registrado em: 30 Mar 2021 14:13
Localização: São José dos Campos

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por Jefferson81br »

Boa tarde a todos.

Primeiramente desculpe se a postagem esta no lugar errado, espero que aqui seja o lugar certo.

Meu nome é Jefferson, sou engenheiro eletricista e atuo na área de suporte a informatica. Não atuo em programação,
meus conhecimentos nessa área são limitados.

Estou com uma situação que acredito os senhores podem ajudar.

Um novo cliente, possui/possuía um sistema de gerenciamento feito em clipper, que rodava em uma cpu com DOS puro.
Depois de uns 15 anos funcionando bem, temos que o disco rígido apresentou problema.

Consegui restaurar 95% de tudo mas faltou alguns arquivos.

Basicamente tenho o executável e a base de dados, os arquivos .dbf todos ok. (código fonte também possuo)

O sistema usava um arquivo (siasca.snh) que ficava na raiz do C: para validar a senha do usuário. Esse arquivo não existe
mais nem temos copia de backup. Sem esse arquivo, o sistema apresentava erro, indicando a falta desse arquivo e encerrava.

Criei uma base de dados vazia e coloquei no lugar, o sistema apresentou erro indicando agora o campo que buscava (CODSENHA)

Coloquei dentro do novo arquivo o campo CODSENHA e o valor a senha (XXXX).

Temos agora o sistema ate reconhece, mas sempre acusa a senha errada.

Analisando o código fonte, vejo que o programador criou uma "criptografia" na senha digitada que será comparada com o valor do arquivo.

Penso se conseguir interpretar essa codificação, e saber qual o valor resultante de uma senha 1234, por exemplo, e salvar esse valor no
arquivo de senha, conseguirei recuperar o sistema desse cliente.

Se alguém puder ajudar, ou dar alguma sugestão agradeço.

abaixo a parte do código referente a senha.

Grato

Código: Selecionar todos

FUNCTION SENHA

MENSAGEM("Digite o nome do operador")
JANELA(7,16,17,62,"Acesso ao sistema")
COR("MENU")
@10,22 CLEAR TO 14,56
@11,24 SAY "Operador :"
@13,24 SAY "Senha    : [úúúúúúúúú]"
M->SENHA=""
M->OPERADOR=SPACE(20)
M->TEC=0
@11,35 GET M->OPERADOR PICT "@!" VALID .NOT. EMPTY(M->OPERADOR)
SET CURSOR ON
READ
SET CURSOR OFF
MENSAGEM("Digite a senha para acesso ao sistema")
SETCOLOR(CONTECOR[3])
@13,35 SAY "[úúúúúúúúú]"
FOR M->P_SENHA=36 TO 44
   M->TEC=INKEY(0)
   IF M->TEC=8
      IF M->P_SENHA>36
         M->P_SENHA=M->P_SENHA-1
         @13,M->P_SENHA SAY "ú"
         M->SENHA=SUBS(M->SENHA,1,LEN(M->SENHA)-1)
      ENDIF
      M->P_SENHA=M->P_SENHA-1
   ELSE
      M->SENHA=M->SENHA+CHR(M->TEC)
      IF M->TEC=13 .OR. M->TEC=27
         EXIT
      ENDIF
      @13,M->P_SENHA SAY "þ"
   ENDIF
NEXT
M->SENHA=UPPER(M->SENHA)
COD_FICA(@SENHA)
M->NOM_ARQ="SIASCA.SNH"
IF .NOT. FILE(M->NOM_ARQ)
   SET CURSOR OFF
   BEEP()
   MENSAGEM("Arquivo de senhas n„o se encontra dispon¡vel",3)
   SET COLOR TO W
   SET CURSOR ON
   CLEAR
   QUIT
ENDIF
USE &NOM_ARQ
GOTO TOP
M->NIVEL=" "
DO WHILE .NOT. EOF()
   IF CODSENHA==M->SENHA 
      M->NIVEL=ACESSO
      EXIT
   ENDIF
   SKIP
ENDDO
USE
SET CURSOR ON
RETURN M->NIVEL
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

Código: Selecionar todos

   cSENHA := UPPER( cSENHA )
   COD_FICA( @cSENHA )

   USE ( cFileName )
   GOTO TOP
   cNIVEL := " "
   DO WHILE .NOT. Eof()
      IF field->CODSENHA == cSENHA
         cNIVEL := field->ACESSO
         EXIT
      ENDIF
      SKIP
   ENDDO
   USE

   RETURN cNIVEL
A função Cod_Fica() é que faz a criptografia.
E o nível é o que vai determinar o que vai poder fazer.
Ela não faz parte desse fonte.

no arquivo precisa os campos CODSENHA e ACESSO

Só pra curiosidade:

Cod_Fica( @cVariavel )

O @ (arrôba) significa que a função Cod_Fica() provavelmente altera o conteúdo dessa variável (provavelmente criptografando)
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Jefferson81br
Usuário Nível 1
Usuário Nível 1
Mensagens: 3
Registrado em: 30 Mar 2021 14:13
Localização: São José dos Campos

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por Jefferson81br »

Segue a função

Código: Selecionar todos

FUNCTION COD_FICA

PARA CODI_GO
IF LEN(M->SENHA)<9
M->SENHA=M->SENHA+SPACE(9-LEN(M->SENHA))
ENDIF
M->COD=M->CODI_GO
M->CODI_GO=""
FOR M->X=9 TO 1 STEP -1
M->CODI_GO=M->CODI_GO+SUBS(M->COD,M->X,1)
NEXT
M->CODI_GO=SUBS(M->CODI_GO,4,3)+SUBS(M->CODI_GO,1,3)+SUBS(M->CODI_GO,7,3)
M->COD=""
FOR M->X=1 TO 9
   IF M->X/2=INT(M->X/2)
      IF ASC(SUBS(M->CODI_GO,M->X,1))=255
         M->COD=M->COD+CHR(0)
      ELSE
         M->COD=M->COD+CHR(ASC(SUBS(M->CODI_GO,M->X,1))+1)
      ENDIF
   ELSE
      IF ASC(SUBS(M->CODI_GO,M->X,1))=0
         M->COD=M->COD+CHR(255)
      ELSE
         M->COD=M->COD+CHR(ASC(SUBS(M->CODI_GO,M->X,1))-1)
      ENDIF
   ENDIF
NEXT
M->CODI_GO=M->COD
Jefferson81br
Usuário Nível 1
Usuário Nível 1
Mensagens: 3
Registrado em: 30 Mar 2021 14:13
Localização: São José dos Campos

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por Jefferson81br »

Para caso aja interesse, o arquivo completo.
Anexos
CSP0001.PRG
(49.26 KiB) Baixado 318 vezes
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

Pensando bem.....
Talvez mais fácil fazer o seguinte:

Código: Selecionar todos

Cod_Fica( @Senha )
Alert( Senha )
Isso vai mostrar a senha criptografada.

e/ou gravar direto no arquivo.

Código: Selecionar todos

Cod_Fica( @Senha )
use ( arquivo )
Append blank
replace CodSenha WITH Senha, Nivel WITH "3"
use
QUIT
Coloque isso pra gravar, e depois retire.
Ainda resta saber o que vai ser gravado como nível, se é número/letra/etc, ou se nível 0 é máximo, ou se nível 3 ou se nível 9, etc.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

Ou mais fácil ainda, bloqueie a criptografia, e grave direto

// Cod_Fica( @Senha )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

Código: Selecionar todos


FUNCTION COD_FICA( Codi_go )

   // passso 1: 9 caracteres, numa variável que não serve pra nada
   IF Len( SENHA ) < 9
      SENHA := SENHA + SPACE( 9 - Len( SENHA ) )
   ENDIF
   
   // passo 2: inverte a string
   COD     := CODI_GO
   CODI_GO := ""
   FOR X = 9 TO 1 STEP -1
      CODI_GO := CODI_GO + Substr( COD, X, 1 )
   NEXT
   
   // passo 3: pega as 3 do meio, as 3 primeiras, e as 3 últimas letras
   CODI_GO := Substr( CODI_GO, 4, 3 ) + Substr( CODI_GO, 1, 3 ) + Substr( CODI_GO, 7, 3 )
   
   // passo 4: caractere ascii par soma 1, caractere ímpar tira 1
   // nem sei se precisava checar 255 e 0, já que nem dá pra digitar isso
   COD := ""
   FOR X = 1 TO 9
      IF X / 2 = INT( X / 2 )
         IF Asc( Substr( CODI_GO, X, 1 ) ) = 255
            COD = COD + CHR(0)
         ELSE
            COD = COD + CHR( ASC( Substr( CODI_GO, X, 1 ) ) + 1 )
         ENDIF
      ELSE
         IF Asc( Substr( CODI_GO, X, 1 ) ) = 0
            COD := COD + CHR(255)
         ELSE
            COD := COD + CHR( ASC( Substr( CODI_GO, X, 1 ) ) - 1 )
         ENDIF
      ENDIF
   NEXT
   CODI_GO := COD

   RETURN Nil

Pensando bem.... como deixa com 9 caracteres a variável errada, vai acabar existindo caractere 0
À primeira vista, gravando codSenha com Replicate( Chr(255), 9 ) aceitaria senha em branco.

Não, errei, porque par soma e ímpar tira, seria intercalado 255 e 1, porque no ímpar quando 0 assume 255, e no par assume 1
Pad( replicate( Chr( 255 ) + Chr(1), 5 ), 9 )

replicate() para multiplicar a ocorrência 5 vezes, resultando 10 caracteres, e pad() pra deixar só 9.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
rochinha
Administrador
Administrador
Mensagens: 4664
Registrado em: 18 Ago 2003 20:43
Localização: São Paulo - Brasil
Contato:

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por rochinha »

Amiguinhos,

A codificação segue e passa por uma função de critica, a qual deve retornar algum resultado que permita passar ou não?

Torne esta função como dummy. ou seja, a função continua lá, mas não executa o código interno mas retornar algum valor que permita ser sempre válido.

Supondo que a função tenha de retornar .T. para passar como liberado force a variavel retornada como sendo sempre .T.

Código: Selecionar todos

FUNCTION COD_FICA( Codi_go )
    RETURN .t.
Caso a função calcule o valor existente no campo e o resultado tenha de ser sempre 9999:

Código: Selecionar todos

FUNCTION COD_FICA( Codi_go )
    RETURN 9999
OPS! LINK QUEBRADO? Veja ESTE TOPICO antes e caso não encontre ENVIE seu email com link do tópico para [url=mailto://fivolution@hotmail.com]fivolution@hotmail.com[/url]. Agradecido.

@braços : ? )

A justiça divina tarda mas não falha, enquanto que a justiça dos homens falha porque tarda.
Avatar do usuário
mauricioportela
Usuário Nível 2
Usuário Nível 2
Mensagens: 95
Registrado em: 29 Jul 2016 04:22
Localização: Vitoria da Conquista/Bahia

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por mauricioportela »

o fragmento que complica ta na comparacao

(X/2) == INT(X/2)

Código: Selecionar todos

functio main()
    COD_FICA("MAURICIO")
return nil

FUNCTION COD_FICA( CODI_GO )
    SENHA = CODI_GO
    IF LEN(SENHA) < 9
        SENHA += SPACE(9-LEN(SENHA))
    ENDIF
    COD = CODI_GO
    CODI_GO = ""
    FOR X = 9 TO 1 STEP -1
        CODI_GO += SUBSTR(COD,X,1)
    NEXT
    CODI_GO = SUBSTR(CODI_GO, 4, 3) + SUBSTR(CODI_GO, 1, 3) + SUBSTR(CODI_GO, 7, 3)
    COD=""
    FOR X = 1 TO 9
        // =====================================================================
        IF (X/2) == INT(X/2)
        // =====================================================================
            IF ASC(SUBSTR(CODI_GO, X, 1)) == 255
                COD += CHR(0)
            ELSE
                COD += CHR(ASC(SUBS(CODI_GO,X,1))+1)
            ENDIF
        ELSE
            IF ASC(SUBS(CODI_GO,X,1))=0
                COD += CHR(255)
            ELSE
                COD += CHR(ASC(SUBS(CODI_GO,X,1))-1)
            ENDIF
        ENDIF
    NEXT
    CODI_GO = COD
    FOR X = 1 TO 9
        // =====================================================================
        IF (X/2) == INT(X/2)
        // =====================================================================
            IF ASC(SUBSTR(CODI_GO, X, 1)) == 255
                COD += CHR(255)
            ELSE
                COD += CHR(ASC(SUBS(CODI_GO,X,1))-1)
            ENDIF
        ELSE
            IF ASC(SUBS(CODI_GO,X,1))=0
                COD += CHR(0)
            ELSE
                COD += CHR(ASC(SUBS(CODI_GO,X,1))+1)
            ENDIF
        ENDIF
    NEXT
    cod := substr(COD, (len(cod)/2)+1, 9)
    COD2 = ""
    FOR X = 9 TO 1 STEP -1
        cod2 += SUBSTR(cod,X,1)
    NEXT
    CODI_GO = SUBSTR(COD2, 1, 3) + SUBSTR(COD2, 7, 3) + SUBSTR(COD2, 4, 3)
    ? "[reverse]", CODI_GO
se tivesse o arquivo SIASCA.SNH, ficaria mais facil testar.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

mauricioportela escreveu:o fragmento que complica ta na comparacao
(X/2) == INT(X/2)
O que tem a ver, se está apenas testando se a posição é par ou ímpar?
Isso equivale a Mod( x, 2 ) == 0 ou x % 2 == 0

Apenas altere pra mostrar e/ou gravar o resultado e pronto, nem precisa entender o cálculo.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
mauricioportela
Usuário Nível 2
Usuário Nível 2
Mensagens: 95
Registrado em: 29 Jul 2016 04:22
Localização: Vitoria da Conquista/Bahia

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por mauricioportela »

JoséQuintas escreveu: O que tem a ver, se está apenas testando se a posição é par ou ímpar?
Isso equivale a Mod( x, 2 ) == 0 ou x % 2 == 0

Apenas altere pra mostrar e/ou gravar o resultado e pronto, nem precisa entender o cálculo.
Ela afeta diretamente o resultado.

Código: Selecionar todos

    COD_FICA("MAURICIO")
    COD_FICA("TESTE")
    COD_FICA("ALFA")
    COD_FICA("CARRO")
...
>>>[ 072 ] -- [ I ]<<<
>>>[ 083 ] -- [ R ]<<<
>>>[ 084 ] -- [ U ]<<<
>>>[ 080 ] -- [ O ]<<<
>>>[ 072 ] -- [ I ]<<<
>>>[ 068 ] -- [ C ]<<<
>>>[ 064 ] -- [ A ]<<<
>>>[ 078 ] -- [ M ]<<<
>>>[ 255 ] -- [   ]<<<
[reverse]  MAURICIO
>>>[ 068 ] -- [ E ]<<<
>>>[ 085 ] -- [ T ]<<<
>>>[ 068 ] -- [ E ]<<<
>>>[ 085 ] -- [ T ]<<<
>>>[ 082 ] -- [ S ]<<<
>>>[ 001 ] -- [   ]<<<
>>>[ 255 ] -- [   ]<<<
>>>[ 001 ] -- [   ]<<<
>>>[ 255 ] -- [   ]<<<
[reverse]    ETE ST
>>>[ 064 ] -- [ A ]<<<
>>>[ 066 ] -- [ A ]<<<
>>>[ 069 ] -- [ F ]<<<
>>>[ 077 ] -- [ L ]<<<
>>>[ 255 ] -- [   ]<<<
>>>[ 001 ] -- [   ]<<<
>>>[ 255 ] -- [   ]<<<
>>>[ 001 ] -- [   ]<<<
>>>[ 255 ] -- [   ]<<<
[reverse]    FAA  L
>>>[ 064 ] -- [ A ]<<<
>>>[ 068 ] -- [ C ]<<<
>>>[ 078 ] -- [ O ]<<<
>>>[ 083 ] -- [ R ]<<<
>>>[ 081 ] -- [ R ]<<<
>>>[ 001 ] -- [   ]<<<
>>>[ 255 ] -- [   ]<<<
>>>[ 001 ] -- [   ]<<<
>>>[ 255 ] -- [   ]<<<
[reverse]    OCA RR
Avatar do usuário
mauricioportela
Usuário Nível 2
Usuário Nível 2
Mensagens: 95
Registrado em: 29 Jul 2016 04:22
Localização: Vitoria da Conquista/Bahia

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por mauricioportela »

Cometi um erro no código.

Corrigido.

Código: Selecionar todos

function main()
    ? codifica("MAURICIO")
    ? codifica("TESTE")
    ? codifica("ALFA")
    ? codifica("CARRO")

    ? decodifica( codifica("MAURICIO") )
    ? decodifica( codifica("TESTE") )
    ? decodifica( codifica("ALFA") )
    ? decodifica( codifica("CARRO") )
return nil

FUNCTION codifica( cCodigo )
    cCodigo := IF((LEN(cCodigo) < 9), cCodigo + SPACE(9-LEN(cCodigo)), cCodigo)
    COD := cCodigo
    cCodigo := ""
    FOR X := 9 TO 1 STEP -1
        cCodigo += SUBSTR(COD,X,1)
    NEXT
    cCodigo := SUBSTR(cCodigo, 4, 3) + ;
               SUBSTR(cCodigo, 1, 3) + ;
               SUBSTR(cCodigo, 7, 3)
    COD := ""
    FOR X := 1 TO 9
        IF (X/2) == INT(X/2)
            COD += IF((ASC(SUBSTR(cCodigo, X, 1)) == 255), ;
                      CHR(0), ;
                      CHR(ASC(SUBSTR(cCodigo,X,1))+1))
        ELSE
            COD += IF((ASC(SUBSTR(cCodigo,X,1)) == 0), ;
                      CHR(255), ;
                      CHR(ASC(SUBSTR(cCodigo,X,1))-1))
        ENDIF
    NEXT
RETURN COD

FUNCTION decodifica( COD )
    cCodigo := COD
    COD := ""
    FOR X = 1 TO 9
        IF (X/2) == INT(X/2)
            COD += IF((ASC(SUBSTR(cCodigo, X, 1)) == 255), ;
                      CHR(255), ;
                      CHR(ASC(SUBSTR(cCodigo,X,1))-1))
        ELSE
            COD += IF((ASC(SUBSTR(cCodigo,X,1)) == 0), ;
                      CHR(0), ;
                      CHR(ASC(SUBSTR(cCodigo,X,1))+1))
        ENDIF
    NEXT
    COD2 := ""
    FOR X := 9 TO 1 STEP -1
        cod2 += SUBSTR(cod,X,1)
    NEXT
    cCodigo = SUBSTR(COD2, 1, 3) + ;
              SUBSTR(COD2, 7, 3) + ;
              SUBSTR(COD2, 4, 3)
RETURN cCodigo
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

O que te complicou foi a função, criada por quem não entende de função.
E você está tentando usar como função, o que não é.
O parâmetro NÃO é a senha.

Código: Selecionar todos

Senha := "aqui_senha"
Codi_go := ""
Cod_Fica( "qualquer_coisa" )
? codi_go
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Ajuda com arquivo de senha perdido/ criptografia senha

Mensagem por JoséQuintas »

E na prática não pode usar só pra mostrar, porque poderia conter chr(0)

Código: Selecionar todos

Senha := "aqui_senha"
Codi_go := ""
Cod_Fica( "qualquer_coisa" )
? codi_go

FOR EACH cLetra IN codi_go
   ? cLetra,  Asc( cLetra )
NEXT
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Responder