NOME

UOLbot - interface Perl para bate-papo do UOL


PLATAFORMAS SUPORTADOS

Teoricamente, todos onde roda o perl. Oficialmente, foi testado em:


RESUMO

  #!/usr/bin/perl
  use UOLbot;
  my $bot = new UOLbot (Nick => 'uolbot');
  $bot->login ('batepapo4.uol.com.br:3999');
  $bot->send ("Hello World!");
  $bot->logout;
  exit;


DESCRIÇÃO

O UOLbot é um módulo Perl que implementa interface para webchat (batepapo) do UOL (http://www.uol.com.br/). Basicamente, a idéia é poder acessar as funções comunicativas do chat de fora do navegador. No caso, à partir de um programa escrito em Perl. Um detalhe em destaque: a intenção é implementar interface completa. Por exemplo, clientes tais como Jane, UOLME e Chat-Nóia 666 implementam só um pouco à mais do que parte interativa. ``O grosso'' do trabalho em tais clientes é feito pelas DLLs do Internet Explorer. Já o UOLbot é independente de Internet Explorer assim como é independente do Windows como todo.

Então, conforme o próprio nome diz, você pode escrever bots de propaganda (robôs de propaganda que andam de sala em sala enchendo o saco das pessoas) utilizando UOLbot. Você também pode fazer algo útil como o primeiro cliente de batepapo UOL que seja cross-platform. Fiz de tudo para tais tarefas sejam mais simplificadas possíveis, apenas repare no exemplo acima ;)

Bom, qualquer coisa, esse projeto está quase sempre em expansão. Comecei aplicando uma engenharia reversa para saber como o Microsoft Internet Explorer 6.0 interage com servidores do UOL (sim, a lógica de operação é do IE do começo ao fim), e atualmente tenho em mãos um módulo orientado à objetos (híbrido, para ser honesto) que faz virtualmente tudo o que você faria num webchat.

Obs: antes que me pergunte, ``eu estou lendo em português aqui, então por que send e não enviar, ou logout ao invés de sair?'' A razão é simples: o ``resto'' do perl está em inglês, certo? Por mim, fica estranho ler e entender o que faz algo como

  next if $bot->enviar and not scalar $bot->usuarios;


INTRODUÇÃO

Agora, o princípio ativo. Antes de tudo, você deve criar uma instância do bot:

  my $bot = new UOLbot (Nick => 'uolbot');

O parâmetro Nick especifica o nickname do bot. Você pode passar outros, que serão descritos posteriormente. Você também pode não passar nenhum, aí o seu bot será um discreto ``unnamed''. Você pode ter várias instâncias, só não sei qual o sentido disso. Vários robôs para várias salas em um só programa?

Pronto, você criou o seu bot... E agora? Ele deve entrar numa sala, né?

  $bot->login ('batepapo4.uol.com.br:3999');

(ótima sala para propaganda, eheheh) Aí você passa a URL da sala. É o único parâmetro necessário. É claro que ter que saber essa URL é um pé no saco, você pode entrar na sala só sabendo o seu nome/número. Mas isso é para depois.

Opa, mas espere um pouco. Você já deve ter percebido aqueles códigos de verificação anti-spam, né (antes não existia isso não)... O que fazer agora? NADA. Lhes apresento orgulhosamente o UOL::OCR!!! É um sub-componente composto por filtros digitais de imagem e um programa de OCR (Optical Character Recognition), atualmente o jocr (http://jocr.sourceforge.net). Tal componente trata dos códigos de verificação para você, e aparentemente muito bem ;)

Bom, e estando na sala, o que fazer? Falar!

  $bot->send ("Hello World!");

``Oi mundo'' :P Sem comentários aqui.

Quando você ``falou'' tudo o que quis, tchau para todos!

  $bot->logout;

Isso é o básico. Se não entendeu, pare por aqui.


REQUISITOS


CONSTRUTOR

new ([ARGS])
Construtor para o bot. Retorna a referência para objeto UOL::bot. Argumentos ARGS devem ser passados em forma:
  new (Chave1 => 'valor1',
       Chave2 => 2);

Note que alguns dos argumentos você poderá alterar posteriormente com métodos apropriados, e outros não. Argumentos válidos (todos opcionais):

UA
referência para objeto LWP::UserAgent externo (é criada instância interna por default)

Nick
o nickname (valor default é ``unnamed'')

Color
a cor do nickname (valor default é 0)

Obs: valores possíveis são:

  0 - Preto
  1 - Vermelho
  2 - Verde
  3 - Azul
  4 - Laranja
  5 - Cinza
  6 - Roxo

Avatar
define ``carinha'' na frente do nick (número inteiro, para ser descoberto na tentativa e erro :(

Obs: a ``carinha'' só vai aparecer se você for autenticado com auth!

Obs2: pra tirar a ``carinha'' já definida, chame $bot->avatar (-1).

Fast
se setado em 1 faz UOLbot pular passos desnecessários de autenticação/login na sala. Pode fazer diferença em conexões lentas, porém pode gerar incompatibilidades, cuidado ao usar!

Tries
número de tentativas para processar/reentrar código de verificação. Tenha em mente que o OCR embutido pode errar para algum tipo de fonte/fundo/texto, porém quem sabe se na próxima ele acerta? Default é 3.

Auth_Magic
preconfigura o cookie mágico que UOL utiliza para saber se o usuário é registrado. Uma boa idéia é não tocar nisso, se quiser experimentar, primeiro dê um auth com login/senha válidos, depois dê um
  print $bot->auth_magic, "\n";

depois copie o que for impresso e cole no

  my $bot = new UOLbot (Auth_Magic => ...);

ImgCode_Handler
referência para a rotina que vai processar a imagem com código de verificação. A minha sugestão é que você não toque nisso. O default é tentar carregar um OCR aqui, se falhar, então a URL da imagem com código de verificação é impressa e você (usuário) tem que ler/digitar... Argh. De qualquer forma, a sintaxe é:
  ImgCode_Handler => \&my_imgcode_handler
  ...
  sub my_imgcode_handler {
     my ($req, $ua) = @_;
     # $req é istância HTTP::Request
     # $ua é instância LWP::UserAgent
     my $resp = $ua->request ($req);
     ...
     return $code;
  }

No caso:

$req é instância HTTP::Request da imagem-código $ua é instância LWP::UserAgent atualmente usada pelo UOLbot $code é código de 4 caracteres [a-z0-9]

Listen_Handler
referência para a rotina que vai processar as informações recebidas da sala (indefinido por default). Por exemplo:
  Listen_Handler => sub { print $_[0] }

imprime qualquer coisa recebida e

  Listen_Handler => \&listen_handler
  ...
  sub listen_handler {
     my $data = shift;
     ...
     return;
  }

define a sub-rotina listen_handler como handler de 'escuta'. Nesse caso, variável $data recebe pacotes com código HTML recebidos.

Obs: lembre que nem sempre há uma mensagem em um pacote. O servidor (ou buffer do sistema operacional) pode juntar vários pacotes num só.


MÉTODOS

Os métodos do UOLbot são:

ua
nick
color
avatar
fast
tries
auth_magic
imgcode_handler
listen_handler
Métodos para ler/definir os parâmetros definidos pelo new.

Obs: Você pode ler os valores a qualquer momento, mas só poderá definir quando a instância não estiver logada com login!

list_subgrp (SUBGRP)
Enumera as salas de bate-papo de um sub-grupo SUBGRP. O tal sub-grupo é o documento onde nomes das salas, suas URLs e suas lotações são fornecidos. list_subgrp é simplesmente uma interface para esse documento. Parâmetro SUBGRP é uma string com URL de formato 'http://batepapo.uol.com.br/bp/excgi/salas_new.cgi?ID=idim_he.conf' ou então simplesmente 'idim_he.conf'. Os dois são equivalentes. Quando você usa list_subgrp antes de login, SUBGRP é salvo e utilizado como REF de login automaticamente. O método retorna um array de hashes se tiver sucesso e () se houver falha. O array retornado pode ser expandido com:
  my @room = $bot->list_subgrp ('idim_he.conf');
  foreach $room (@room) {
     print $room->{URL}, "\n",
           $room->{Title}, "\n",
           $room->{Load}, "\n\n";
  }

onde URL é a URL da sala de bate-papo, Title é o título dela e Load é o número de pessoas na sala (0-40, -1 significa ``sala lotada'').

search (STRING)
Busca por usuário com STRING contido no nickname em todas as salas. Retorna () caso nenhum seja encontrado ou array semelhante ao do list_subgrp:
  my @room = $bot->search ('uolbot');
  foreach $room (@room) {
     print $room->{Nick}, "\n",
           $room->{URL}, "\n",
           $room->{Title}, "\n",
           $room->{Load}, "\n\n";
  }

Onde Nick refere o nickname completo do usuário encontrado, URL é o endereço da sala onde o usuário atualmente se encontra, Title é o título da mesma (cortado, foi mal) e Load é quantidade de pessoas presentes na mesma sala.

brief (ROOM)
``Espia'' na sala sem entrar nela. Retorna 0 se falha. Caso tiver sucesso,
  1. guarda a lista com nomes de usuários para depois ser vista com users

  2. passa o fragmento da conversa para rotina definida em Listen_Handler

  3. retorna 1

auth ([USER, PASS])
Autentica usuário registrado. Permite entrar nas salas com mais de 30 pessoas e usar ``carinha'' na frente do nick. USER é o nome de usuário em forma 'nome@uol.com.br' e PASS é a senha. Agora, o mais velho hack de sistema de chat... Omita USER e PASS e terás todos os privilégios de um usuário registrado sem ser um ;)

Retorna 0 se houver falha (username/senha inválidos) e 1 se tiver sucesso.

Obs: você deve autenticar antes de efetuar login!

Obs2: auth utiliza conexão encriptada via SSL automaticamente quando o módulo Crypt::SSLeay é encontrado no sistema. Sem esse módulo, a conexão efetuada é insegura e a senha pode ser vista por pessoas mal-intencionadas! Duvido muito, mas o que custa fazer direito?!

login (ROOM [, REF])
Efetua login na sala ROOM de bate-papo. Chama internamente imgcode_handler. Parâmetro ROOM consiste de uma string de formato "http://batepapo4.uol.com.br:3999/". Se você for preguiçoso como eu, pode usar "batepapo4.uol.com.br:3999" apenas. Parâmetro REF, opcional, é o Referer, o documento que continha o link para ROOM. Se você omitir o REF, valor 'http://batepapo.uol.com.br/bp/excgi/salas_new.shl' será usado automaticamente. Se você estiver usado list_subgrp ou search antes de login, a URL de sub-grupo listado será usada como REF. Leia mais sobre list_subgrp/search.

Retorna 0 se houver falha e 1 se tiver sucesso. A ``falha'' mais provável é que a sala esteja cheia. Utilize o login_error para obter mais detalhes sobre a falha ocorrida.

is_logged
Retorna não-0 se o bot estiver atualmente numa sala de bate-papo e 0 caso contrário.

Detalhes Técnicos: Para ser exato, retorna o número de tentativas de efetuar a verificação.

encode
Retorna a parte ``encriptada'' da URL da última imagem processada contendo código de verificação.

decode
Retorna o código lido.

is_auth
Retorna 1 se o bot estiver autenticado como usuário registrado do UOL.

login_error
Retorna o código do erro durante login:
  0     - sucesso
  1     - nickname já foi utilizado
  2     - sala está cheia
  3     - código de verificação incorreto
  undef - erro desconhecido (ver valor de $!)

users
Retorna array de nicknames de usuários atualmente presentes na sala de bate-papo. Os dados são atualizados toda vez que você efetua login, send ou brief. Desculpe, não fui eu quem inventou isso... Retorna no mínimo o próprio nickname (a sala não está vazia se você está lá ;) ou () no caso de falha. Detalhe: se você usou brief, a sala pode estar vazia portando () não significa erro.

send ([MSG] [, ATTR])
Envia mensagem MSG para sala de bate-papo. Possui 4 sintaxes:
  1.  $bot->send ('mensagem 1');

    a mais simples, envia string 'mensagem 1'

  2.  $bot->send ('mensagem 2', To => 'TODOS', Action => 15);

    envia string 'mensagem 2' com atributos To e Action explicados abaixo

  3.  $bot->send (Msg => 'mensagem 3', To => 'TODOS', Action => 15);

    o mesmo de cima para 'mensagem 3'

  4.  $bot->send ();

    sintaxe mais obscura, não envia nada, apenas atualiza a lista que pode ser obtida com método users. De novo, não fui eu quem inventou!

Agora, sobre atributos ATTR. São todos opcionais (forma Chave => 'Valor'), aqui está a lista com uma breve explicação:

Msg
a mensagem em si, string (só pode ser usado com sintaxe 3, ignorado na sintaxe 2!)

Action
ação, valor inteiro. Ações possíveis:
  0  - fala para (default)
  1  - pergunta para
  2  - responde para
  3  - concorda com
  4  - discorda de
  5  - desculpa-se com
  6  - surpreende-se com
  7  - murmura para
  8  - sorri para
  9  - suspira por
  10 - flerta com
  11 - entusiasma-se com
  12 - ri de
  13 - dá um fora em
  14 - briga com
  15 - grita com
  16 - xinga
  18 - IGNORAR mensagens de
  19 - só receber mensagens de
  20 - não IGNORAR mais

To
o nickname do receptor da ação Action, string. Valor default é 'TODOS'.

Obs1: não necessariamente é alguém que esteja na sala. Isto é, você pode fazer:

  $bot->send ('bots do UOL, uní-vos!', To => 'bots renegados');

desde que não seja uma mensagem reservada (Reserved => 1)!

Obs2: independentemente do valor do To, todos os usuários da sala irão ler a mensagem. Para mensagens privadas, use Reserved.

Reserved
pode ser 1 ou 0. Quando 1, a mensagem é enviada reservadamente para nickname To. Valor default é 0.

Sound
som a ser enviado, inteiro. Sons possíveis:
  0  - nenhum (default)
  14 - Ahn???
  15 - Bang!
  16 - Banjo
  17 - Dinossauro
  18 - Fiu-fiu
  19 - Ocupado
  20 - Oinc
  21 - Pigarro
  22 - Smack!
  23 - Susto
  24 - Telefone
  25 - Tôlôca
  26 - Tosse
  07 - Como é?
  08 - Não entendi

Icon
ícone a ser enviado, inteiro. Ícones possíveis:
  0  - nenhum (default)
  38 - Assustado
  27 - Bocejo
  23 - Careta
  30 - Dentuço
  18 - Desejo
  31 - Eca !
  32 - Gargalhada
  33 - Indeciso
  34 - Louco
  28 - Na praia
  35 - Ohhh !
  20 - OK!
  36 - Piscada
  37 - Raiva
  19 - Smack!
  21 - Sorriso
  26 - Zangado

Retorna 0 se houver falha e 1 se tiver sucesso.

Obs: aparentemente o servidor não aceita mensagens > 200 bytes.

scroll (TIMEOUT)
Obs: Provavelmente a parte mais chatinha... Mas indispensável se você quer comunicação bidirecional, isto é, o seu bot envia E recebe dados.

O scroll visa limpar buffers de entrada e enviar dados para sub-rotina definida em Listen_Handler (leia mais sobre argumentos de new). Se o listen_handler for omitido então os buffers serão limpos e a rotina retornará sucesso (1). Só retorna 0 se houver quebra inesperada de conexão.

O parâmetro TIMEOUT é o tempo que o scroll deva esperar até retornar caso o buffer esteja vazio, em segundos. Resumindo, scroll() ou scroll(0) retorna imediatamente (timeout 0). scroll(10) aguarda 10 segundos pelo dado. scroll(-1) pausa o programa até que um dado apareça no buffer.

O scroll é chamado automaticamente pelos métodos login, logout e send, portando, não há como o seu Listen_Handler perder algum dado. Porém, se você quiser mais controle, rode um scroll com timeout razoável sempre que estiver esperando alguma resposta do servidor.

Obs: Alguém aí pensou fork? Acredite em mim, não vale a pena! Eu comecei a desenvolver bot bifurcado, com um child para entrada (rodando só while ($bot->scroll(-1)) { ... }) e outro para saída (rodando $bot->send(...)). A sincronização dos dois virou um inferno e o ActivePerl, meu plataforma principal, não era muito amigo do fork. Se você pensar um pouco, verá que o problema em questão é totalmente linear, nunca duas ações são feitas em paralelo. Agora, se você estiver usando plataforma UNIX e não quiser se preocupar onde pôr o scroll, coloque antes do login:

  $SIG{ALRM} = sub { $bot->scroll; alarm 1 };
  alarm 1;

Se você está vendo essa técnica pela 1-a vez, conforme-se com o que já tem.

logout
Efetua logout da sala de bate-papo. Retorna 0 se houver falha e 1 se tiver sucesso.


BUGS

Testei rigorosamente esse módulo, afinal por que a idéia é que um bot rode 24 horas por dia 7 dias por semana sem manutenção.

Porém sempre há coisas que não planejamos afinal, tais como:

Outra coisa... Olha a data desse arquivo. Nessa data UOLbot estava funcionando, pode ter certeza. Se não está agora, é porque pessoal do UOL alterou o sistema de webchat. Sinto muitíssimo... O que você tem a fazer é ou procurar versão mais atual de UOLbot ou adaptar o código desse aqui. Não deve ser difícil, fiz código o mais claro e limpo que pude, até comentei tudo (ôôô)!

O mesmo se aplica a qualquer valor ou tabela citados aqui. O UOL muda constantemente o seu sistema de webchat, fazer o quê...


REFERÊNCIAS

Vários exemplos distribuídos junto com o módulo:

simples.pl
a aplicação mais simples; listar um sub-grupo, entrar na sala #15, repetir mensagem 5 vezes, sair.

crawler.pl
bot de propaganda; entra em todas as salas nos sub-grupos especificados e deixa uma mensagem.

list.pl
busca em sub-grupos especificados e retorna lista de URLs de salas de bate-papo e seus respectivos títulos.


VERSÃO

2.01


HISTÓRICO


COPYRIGHT

  Copyright (C) por Stanislaw Y. Pusep, Janeiro de 2002
  1. A utilização desse módulo, assim como distribuição do módulo e/ou suas versões (alterações feitas no módulo por terceiros) somente deve ser feita com autorização explicita proveniente do autor.

  2. Aqueles que tem cópia autorizada do módulo tem o direito de gerar versões (alterar o módulo conforme for conveniente a eles). (*)

  3. Qualquer programa feito com utilização desse módulo pode ser usado para quaisquer fins (inclusive lucrativos). (*)

(*)
Desde que não haja infração do item 1.


AUTOR

Nome: Stanislaw Y. Pusep

E-Mail: stanis AT linuxmail DOT org

Homepage: http://sysd.org/