UOLbot - interface Perl para bate-papo do UOL
Teoricamente, todos onde roda o perl. Oficialmente, foi testado em:
#!/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;
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;
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.
new ([ARGS])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):
LWP::UserAgent externo (é criada instância interna por default)
Obs: valores possíveis são:
0 - Preto 1 - Vermelho 2 - Verde 3 - Azul 4 - Laranja 5 - Cinza 6 - Roxo
Obs: a ``carinha'' só vai aparecer se você for autenticado com auth!
Obs2: pra tirar a ``carinha'' já definida, chame $bot->avatar (-1).
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!
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 => \&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 => 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ó.
Os métodos do UOLbot são:
uanickcoloravatarfasttriesauth_magicimgcode_handlerlisten_handlernew.
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)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)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)users
passa o fragmento da conversa para rotina definida em Listen_Handler
retorna 1
auth ([USER, PASS])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])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_loggedDetalhes Técnicos: Para ser exato, retorna o número de tentativas de efetuar a verificação.
encodedecodeis_authlogin_error0 - sucesso 1 - nickname já foi utilizado 2 - sala está cheia 3 - código de verificação incorreto undef - erro desconhecido (ver valor de $!)
userslogin,
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])MSG para sala de bate-papo. Possui 4 sintaxes:
$bot->send ('mensagem 1');
a mais simples, envia string 'mensagem 1'
$bot->send ('mensagem 2', To => 'TODOS', Action => 15);
envia string 'mensagem 2' com atributos To e Action explicados abaixo
$bot->send (Msg => 'mensagem 3', To => 'TODOS', Action => 15);
o mesmo de cima para 'mensagem 3'
$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:
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
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.
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
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)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
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:
É resultado dificilmente evitável do progresso do UOLbot. Começa-se
de um jeito, aí muda-se de idéia e termina de um jeito totalmente diferente.
Com certeza você deve estar se perguntando algo do tipo: ``mas para quê dar
um nick à instância que vai apenas checkar a sala?'' ou então: ``não seria
mais fácil encapsular o endereço da sala em HTTP::Request por exemplo,
afinal vira e mexe aparece URL de um jeito ou de outro!''. A pergunta é:
a funcionalidade é prejudicada? Caso contrário, para que perder tempo
arrumando coisa insignificante, afinal, não é um código para massas ;)
Win32
Calma, calma, você pode executar o UOLbot num plataforma Win32.
O grande inconveniente é eu não ter o port do jocr necessário e
biblioteca Image::Magick para testar funções OCR...
Aliás, vi que as vezes há falhas muito estranhas no LWP. Uma hora
tá tudo OK, outra hora não funciona. Eu fiz testes com
ActivePerl 5.6.1 Build 632, utilizando Windows 98, Windows 98 SE
e Windows XP Professional.
O primeiro e o terceiro não apresentaram falhas, o segundo apresentou raramente. Mas
na minha opinião pessoal, eu não confiaria em nada feito pela Micro$oft.
Não confiaria nem nos softwares livres rodando em cima de produtos da
Micro$oft. Portando, aqui vai uma dica que vai te livrar de muitos problemas:
use Linux.
O mínimo esperado do usuário é que passe parâmetros corretos; não passe string onde um número é esperado e nem passe expressão regular onde era para pôr referência ao código...
Ainda assim, fiz o necessário para proteger o usuário contra dar um
logout antes que seja feito um login, portanto não se desanime.
Grande maioria dos proxies públicos (os normalmente utilizados para anonimizar acessos) não deixa conectar nas portas não-HTTP. Nenhuma das salas de bate-papo reside na porta HTTP (80). E então?
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ê...
Vários exemplos distribuídos junto com o módulo:
2.01
Carp::croak para erros de usuário e
adicionado o método brief. Correções menores na documentação.
1.2 (03/Mar/2002) - adicionados métodos auth e avatar (para tirar
proveito de ser usuário registrado do UOL ;).
1.2a (04/Mar/2002) - atualizações na documentação.
1.3 (27/Mar/2002) - reestruturado o processo de login devido às alterações
feitas nos servidores do UOL. Agora você deve dar um join na sala escolhida,
obter o código de verificação e completar operação com login. Maldição!
1.4 (22/Jul/2002) - Código levemente reestruturado para compatibilidade com
módulo OCR (para reconhecimento do código de verificação) que estou fazendo.
Algumas correções menores também.
2.0 (04/Ago/2002) - Código fortemente reestruturado. Muitas mudanças.
Módulo UOL::OCR incluído.
2.01 (06/Dez/2002) - Correção menor devido à atualização de protocolo nos servidores do UOL.
Copyright (C) por Stanislaw Y. Pusep, Janeiro de 2002
(*)
Qualquer programa feito com utilização desse módulo pode ser usado
para quaisquer fins (inclusive lucrativos). (*)
(*)item 1.
Nome: Stanislaw Y. Pusep
E-Mail: stanis AT linuxmail DOT org
Homepage: http://sysd.org/