domingo, 26 de abril de 2009

Sawfish

O Sawfish é um dos softwares da lista dos que eu não gostaria de parar de usar. Assim como o Emacs, é o tipo de software que, depois que se entende e aprende a usar, é difícil de largar.

O Sawfish durante algum tempo foi o gerenciador de janelas do ambiente de desktop Gnome. Por razões ainda não muito claras para mim, foi substituído pelo Metacity.

Assim como o Emacs, um dos grandes diferenciais do Sawfish é o fato de ser programável em uma linguagem de alto nível da família Lisp. Sawfish usa a linguagem rep (Read, Eval, Print), a qual inicialmente foi inspirada por Elisp (Emacs Lisp). A concepção do Sawfish segue a mesma linha do Emacs: prover uma API em uma linguagem de alto nível para desenvolvimento voltado às aplicações a que se destina (abstração). Manipulação de texto no caso do Emacs e gerenciamento de janelas no caso do Sawfish. Com base na API de alto nível, os aplicativos são desenvolvidos. Assim são desenvolvidos o Emacs e o Sawfish. A maior parte do código do Emacs é em Elisp e a maior parte do código do Sawfish é em rep.

O fato de prover uma API para desenvolvimento em uma linguagem de alto nível faz com que o Sawfish seja altamente (e facilmente!) personalizável e extensível. Além das possibilidades de configuração e extensão através de código em rep, Sawfish também dispõe de um configurador gráfico, o qual, por baixo dos panos, apenas gera e executa código rep para configurar o gerenciador de janelas (similar à interface para personalização do Emacs).



Seguindo a tradição de linguagens Lisp e de aplicativos que usam Lisp como linguagem de extensão/implementacao, Sawfish também oferece um REPL para avaliação de expressões rep. Abaixo está um exemplo de sessão com o REPL do Sawfish:

$ sawfish-client
sawfish 1.3.3, Copyright (C) 1999-2000 John Harper
sawfish comes with ABSOLUTELY NO WARRANTY; for details see the file COPYING

Enter `,help' to list commands.
user> (define emacs (get-window-by-name-re "emacs.*"))
user> emacs
#<window 1e00011>
user> (window-name emacs)
"emacs@mandolate"
user> (window-visible-p emacs)
t
user> (window-iconified-p emacs)
()
user> (window-dimensions emacs)
(798 . 742)
user> (window-border-width emacs)
0
user> (window-framed-p emacs)
t
user> (window-depth emacs)
0
user> (window-absolute-position emacs)
(68 . 0)
user> (window-sticky-p emacs)
()
user> (move-window-to emacs 200 100)
#<window 1e00011>
user> (window-absolute-position emacs)
(200 . 100)


O Manual de Programação do Sawfish documenta a API para programação e extensão do gerenciador de janelas.

Abaixo está um screenshot com temas pouco usuais do sawfish (cada janela pode ser decorada com um tema diferente).



A seguir está um exemplo de aplicação feita na linguagem de extensão do Sawfish. Os aplicativos no canto superior esquerdo da tela são dockapps (aqui há vários deles). Quando um dockapp é executado em um gerenciador de janelas sem suporte a dock, o aplicativo é mostrado como uma janela normal, com bordas, decorações e respondendo a eventos como qualquer outra janela. Quando o gerenciador de janelas oferece suporte a dockapps, ou quando se usa um programa externo para gerenciar dockapps, eles são mostrados como no screenshot e têm comportamento diferenciado (são exibidos em todas as áreas de trabalho, não são cobertos por outras janelas quando elas são maximizadas etc).



A extensão para gerenciamento de dockapps pode ser obtida em http://paginas.ucpel.tche.br/~mario/english/utils/sawdock/.

sexta-feira, 24 de abril de 2009

Criptografia simples (ingênua)

A seguir está um esquema simples de criptografia para autenticação em páginas web. Não é um esquema seguro e não envolve chaves públicas (criptografia de chaves assimétricas).

O esquema consiste em apresentar para o usuário uma matriz de números aleatórios (puzzle) para que ele possa dali extrair o texto a ser enviado para ser validado. A cada acesso à pagina uma matriz aleatória nova é exibida. Somente o usuário e o software para valição de senha sabem o segredo (chave) para determinar se a senha está ou não correta.

Na implementação mostrada a seguir (em Chicken Scheme), o código para valição de senha verifica se:

  • a senha possui quatro caracteres

  • o primeiro caractere da senha é igual ao caractere do canto superior esquerdo da matriz de números

  • o segundo caractere da senha é igual ao caractere do canto superior direito da matriz de números

  • o terceiro caractere da senha é igual ao caractere do canto inferior esquerdo da matriz de números

  • o quarto caractere da senha é igual ao caractere do canto inferior direito da matriz de números





Ou seja, o validador verifica se a senha corresponde aos números dos quatro cantos da matriz números concatenados no sentido horário, começando pelo canto superior esquerdo.

Obviamente o validador de senha é dos mais simples, mas poderia usar técnicas mais elaboradas como, por exemplo, o código de Beale. Neste caso, o validador teria um texto padrão, o qual seria de conhecimento do usuário, e os números da matriz indicariam a posição das letras no texto. Assim, o usuário digitaria as letras correspondentes às posições do texto indicadas em lugares pré-determinados da matriz (o uso da matriz é uma otimização sobre o código de Beale -- originalmente seriam apresentados apenas os números indicando a posição das letras no texto).

O código de servidor web (extensão spiffy de Chicken) está abaixo (web-server.scm):

#!/usr/bin/csi -script

(use spiffy spiffy-utils web-scheme web-scheme-handler (srfi 1 13))

(spiffy-file-ext-handlers `(("ws" . ,web-scheme-handler)))
(spiffy-tcp-port 8080)
(spiffy-root-path "./")

(start-server)


A implementação do esquema de autenticação está a seguir (index.ws):

(define (make-puzzle)
;; Retorna uma lista de listas de numeros aleatorios entre 0 e 9
;; (inclusive 0 e 9).
(let* ((line-length 40)
(num-columns 10)
(random-line
(lambda ()
(map (lambda (_) (random 10))
(iota line-length)))))
(map (lambda (_)
(random-line))
(iota num-columns))))

(define (valid-passwd? passwd puzzle)
;; Chave (ingenua): a senha corresponde aos numeros dos cantos da
;; tabela de numeros concatenados no sentido horario, comecando pelo
;; canto superior esquerdo.

(define ($ pos)
;; Retorna o caractere da posicao POS em PASSWD, ou #f se POS nao
;; existir em PASSWD.
(handle-exceptions exn #f (->string (string-ref passwd pos))))

(define (check pw-pos key-pos)
(equal? ($ pw-pos) (number->string key-pos)))

(and passwd
(= (string-length passwd) 4)
(check 0 (caar puzzle))
(check 1 (last (car puzzle)))
(check 2 (car (last puzzle)))
(check 3 (last (last puzzle)))))

(define (auth-page #!optional preamble)
;; Pagina de autenticacao.
(ws:page
(let ((puzzle (make-puzzle)))
(center
(if preamble (p preamble) "")
(ws:make-table puzzle)
(form 'method "post"
(input 'type "hidden" 'name "puzzle"
'value (with-output-to-string (cut pp puzzle)))
(input 'type "password" 'name "passwd")
(input 'type "submit"))))))

(let ((passwd (post-var "passwd"))
(puzzle (post-var "puzzle")))
(if (and puzzle passwd)
(if (valid-passwd? passwd (with-input-from-string puzzle read))
(ws:page "Senha correta")
(auth-page "Senha errada!"))
(auth-page)))

Camiseta do projeto Chicken!

Há umas semanas, Felix Winkelmann, autor e principal desenvolvedor do projeto Chicken Scheme, gentilmente me enviou um e-mail informando que me mandaria uma camiseta do projeto Chicken. Hoje, para a minha felicidade, recebi a camiseta. Muito bonita. :-)



Um tempo atrás tentei fazer uma camiseta dessas no site http://www.camisaonline.com.br/ mas fui roubado. Efetuei o pagamento e nunca recebi a camiseta nem resposta para os vários e-mails que enviei para o endereço de contato. Não comprem desse site.