26 de março de 2013

Estruturas de Dados com Delphi - parte I : Filas

Em maior ou menor grau, o trabalho de um programador de computadores envolve lidar com meios de organizar os dados internos de seus programas. Uma organização bem planejada é imprescindível para a implementação de algorítmos eficientes, o que afeta tanto a performance da aplicação quanto sua facilidade de manutenção. As formas de se organizar os dados em um programa são chamadas de Estruturas de Dados.

Pela sua importância, a maioria das linguagens de programação oferecem bibliotecas com implementações genéricas pré fabricadas para as formas tradicionais de organização de dados, tais como listas, pilhas e filas. No caso do Delphi, esses e outros mecanismos estão disponíveis na unit System.Generics.Collections. Neste post, começo a mostrar as principais estruturas existentes nessa biblioteca, complementando a explicação com exemplos práticos em Delphi.

Em primeiro lugar, precisamos compreender como funciona cada uma das estruturas para podermos decidir qual a mais apropriada para cada situação.

Por exemplo, as filas são desenhadas para o cenário onde precisamos tratar uma sequência de valores exatamente na mesma ordem em que esses valores vão surgindo. É o conceito da fila do caixa em uma loja: cada cliente é atendido sequencialmente de acordo com sua posição na fila; novos clientes entram no final da fila para serem atendidos. Em programação, esse conceito pode ser aplicado ao tratamento de requisições enviadas para execução num sistema. O quadro abaixo traz a declaração básica de uma classe Delphi representando uma requisição executável:
TWRequis = class
public
procedure Execute;virtual;abstract;
function Terminou : Boolean;virtual;abstract;
End;
As Collecions definidas pelo Delphi são estruturas de dados genéricas, mais ou menos como as STL do C++. Isso significa que, quando declaramos uma instância dessas estruturas, devemos informar o tipo de dado que essa Collection em particular vai tratar. Para deixar mais claro, veja a declaração da classe que controlará a execução de requisições em nosso exemplo de fila:
TWVerifRequis = class
{ ... }
public
Fila: TQueue<TWRequis>;
procedure DoOnNotify (Sender: TObject; const Item: TWRequis; Action: TCollectionNotification);

constructor Create;
destructor Destroy;override;
procedure InsereRequis(ATipo: integer);
procedure Start;
end;
No exemplo, declarei a fila associada à classe de requisição. Se for necessário, também é permitido associar a tipos atômicos (como integer e string) ou a estruturas (record). Agora, vamos dar uma olhada no construtor da classe:
constructor TWVerifRequis.Create;
begin
Fila := TQueue<TWRequis>.Create();
Fila.OnNotify := DoOnNotify;
end;
Veja que também ao criar uma instância da fila (o TQueue) devemos especificar o tipo de dado com o qual ela está apta a trabalhar. Um outro detalhe é o evento OnNotify; interceptá-lo nos permite reagir a alterações na fila, tais como saber que um novo registro foi incluído ou acabou de ser removido. Em ambos os casos, podemos atualizar o status da fila para o usuário, avisando-o quantos registros restam e qual requisição está sendo processada. Repare ainda que a assinatura do evento reflete o tipo de dado que nossa fila trata, restringindo a resposta do OnNotify a este tipo específico:
procedure TWVerifRequis.DoOnNotify (Sender: TObject;const Item: TWRequis; Action: TCollectionNotification);
begin
{ A requisição que está no início da fila foi removida; então, ela deve ser executada }
if Action = cnRemoved then begin
{ Atualiza o status, notificando o usuário sobre que requisição está em processamento }
NotificaRequisAtual(Item);
Item.Execute;
Item.Free;
end;

{ Atualiza o status, notificando o usuário sobre quantas requisições restam na fila p/ executar }
NotificaQtd (Fila.Count);
end;
As funções mais importantes para essa estrutura de dado são a que acrescenta e a que remove um elemento da fila. Para incluir um novo item ao fim da fila, use o método Enqueue e para remover o elemento que está no início da fila, use Dequeue, como mostra o exemplo a seguir:
procedure TWVerifRequis.InsereRequis(ATipo: integer);
var lRequis : TWRequis;
begin
{ Invoca a factory para criar a requisição correta de acordo com o tipo informado }
lRequis := CriaNovaRequisicao(ATipo);

{ Acrescenta ao fim da lista a nova requsição criada }
Fila.Enqueue(lRequis);
end;

procedure TWVerifRequis.Start;
var lRequis : TWRequis;
begin
{ Enquanto não foi solicitado o término da execução, continua monitorando a fila }
while Not Terminou() do begin
{ Se há elemento na lista, remove-o aqui. Isso dispara o evento OnNotify, permitindo a execução dessa requisição }
if (Fila.Count > 0) then
lRequis := Fila.Dequeue
else
Sleep(1000);
end;
end;
A requisição poderia ter sido executada imediatamente após a chamada ao Dequeue, ao invés de dentro do evento OnNotify. Ambas são soluções aceitáveis e, portanto, optar por uma ou outra abordagem é uma questão de gosto.

Uma última consideração: se, por alguma razão, for preciso descobrir quem é o próximo item da fila sem, no entanto, removê-lo, use o método Extract. Uma aplicação disso é mostrar no status informações sobre a requisição que está aguardando para ser executada.

Esse exemplo foi construído com o Delphi XE2; não encontrei informação a respeito da presença da biblioteca Collection em versões anteriores ou em qual versão ela foi introduzida. No próximo post, falo sobre pilhas (ou stacks) e suas aplicações.

2 de janeiro de 2013

Mudanças no envio de e-mails entram em vigor em 1o de Janeiro de 2013

Com o intuito de reduzir o número de spams e melhorar a segurança no envio de e-mails, o CGI (Comitê Gestor da Internet no Brasil) vem recomendando alterações na forma de se enviar e-mails no país. Em acordo com a Anatel, a Associação Brasileira de Internet e o Sindicato Nacional das Empresas de Telefonia e de Serviço Móvel Celular e Pessoal, algumas alterações já foram implantadas.

Como parte desse acordo, a partir de 1º de Janeiro de 2013 os provedores externos de e-mail deverão desligar o envio de mensagens através da porta 25, substituindo-a pela porta 587. De forma simplificada, uma porta é um canal por onde um computador se comunica com outros computadores (ou com periféricos). São exemplos de provedores externos UOL, BOL, Terra, Zipmail, Speedy, Vivo, GMail e Hotmail. E-mails enviados via modem 3G também estão sujeitos à esta mudança.

A mudança afetará tanto o envio de e-mails através de programas tradicionais de mercado - como o Outlook - quanto aqueles programas que você mesmo tenha construído. É preciso verificar com o provedor do serviço de email utilizado se ele acatará as recomendações, adotando a porta 587 (ou outra) para envio das mensagens; em caso afirmativo, você terá que revisar as configurações dos seus aplicativos para evitar que funcionalidades dependentes do envio de e-mail deixem de operar corretamente.

Empresas que usam servidor de e-mail próprio (como o Exchange) não precisam fazer a conversão, embora isso seja recomendado. Para adotar as recomendações nesse cenário, o TI de sua empresa precisará antes rever as configurações do servidor de e-mail, permitindo que ele envie as mensagens através da porta 587 e exija a autenticação do usuário que deseja fazer o envio.

Reproduzo abaixo matéria a esse respeito publicada no UOL:
Internautas que utilizam configurações antigas em programas de leitura e envio de e-mails, como o Outlook, Windows Mail, Apple Mail ou aqueles instalados no celular, podem não conseguir enviar mensagens a partir de 2013. O Comitê Gestor da Internet no Brasil (CGI) pretende reduzir o volume de spam gerado no país e, por esta razão, solicitou o fim de envios de mensagens sem autenticação, ou seja, sem que o usuário tenha de fornecer login e senha, em todo o território nacional.

A restrição será aplicada para os programas configurados para enviar mensagens (SMTP) pela "porta 25" do computador. Quem usa programas configurados com a "porta 587" ou acessa seus e-mails pelo site do provedor (webmail) não será afetado.

Mudança no envio de e-mails
Para que o envio de mensagens não seja interrompido, é preciso alterar configurações do programa de e-mail, modificando a porta de envio 25 para o valor 587, associado ao padrão SMTPS (protocolo seguro para envio de mensagens).

Gerência da Porta 25
O encerramento da porta 25 é uma recomendação do CGI para por fim a um método de envio de mensagens não solicitadas, os ‘spams’, que se aproveita de conexões não autenticadas.

A mudança foi sugerida em acordo com a Anatel, a Associação Brasileira de Internet (Abranet, que reúne provedores e outras prestadoras de serviço na rede) e o Sindicato Nacional das Empresas de Telefonia e de Serviço Móvel Celular e Pessoal (SindiTelebrasil).

Segundo Eduardo Nager, presidente da Abranet, os provedores estão preparados para a mudança há muito tempo, recomendando a utilização de conexões seguras e configurações atualizadas. Para Nager, a grande mudança em 1º de janeiro se dará na parte de acesso físico, a cargo das operadoras de telecomunicações.

Eduardo Levy, diretor executivo do SindiTelebrasil, informou que o prazo para fechamento da porta 25 é o dia 31 de dezembro, acordado entre as suas filiadas, que incluem Oi, Telefônica, GVT e Embratel, além da TIM. As operadoras Oi - responsável por Oi Velox e Oi Velox 3G - e Telefonica - que vende os serviços Vivo Speedy e Vivo 3G - informaram que já seguem as recomendações do CGI.

Apesar de o fechamento ficar a cargo das operadoras, a notifição aos usuários ficou sob responsabilidade dos provedores de e-mails. Os usuários dos e-mails UOL e BOL recebem comunicados regulares sobre as novas configurações desde 2010.

Além de reduzir o volume de spam enviado pelo Brasil (atualmente o sétimo país no ranking de origem de spams, segundo a empresa de segurança Sophos, e quinto, de acordo com levantamento da Kaspersky Labs), a utilização de conexões seguras pelas portas 587 ou 465 desafoga a conexão dos usuários afetados, seus provedores de acesso e dos serviços de e-mail.

Mais do que isso, a medida ajuda a aumentar a confiabilidade dos serviços de e-mails, ajuda nos esforços para criação de filtros cada vez melhores e pode tirar sites brasileiros de listas internacionais para bloqueio de mensagens indesejadas, segundo Nager.

19 de dezembro de 2012

Personalizando a apresentação de mapas com o Google Maps

Na maioria das vezes, as informações apresentadas num mapa produzido através da API do Google Maps são suficientes para que o usuário rapidamente consiga ver um endereço e seu entorno ou a rota a ser seguida para ir de um ponto a outro. Em certas situações, no entanto, pode ser necessário adicionar ao mapa outras informações para melhor transmitir a ideia correta que se deseja.

Esse tipo de necessidade foi exemplificado quando falei sobre o uso de marcações num mapa para apontar locais de interesse nas proximidades de um determinado endereço. O exemplo pode ser encontrado neste link.

A API do Google Maps nos permite acrescentar informações extras aos mapas através do conceito de camadas que são sobrepostas ao mapa, chamadas de overlays. Para isso, a API disponibiliza um conjunto de classes javascript. Além da já citada Marker, há classes para traçar linhas, delimitar áreas circulares ou retangulares e até mesmo para projetar uma imagem personalizada sobre uma área do mapa.

O overlay mais simples é o Polyline, usado para traçar linhas por sobre o mapa. O quadro abaixo traz código javascript que une com uma linha reta 2 pontos do mapa: a sede da ABC71 e a praça da Sé, em São Paulo:
var mapOptions = {zoom: 10,mapTypeId: google.maps.MapTypeId.ROADMAP};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
geocoder = new google.maps.Geocoder();

var endDe = new google.maps.LatLng(-23.566146,-46.652579);
var endAte = new google.maps.LatLng(-23.550563,-46.633101);
var request = { location: endDe, region: 'BR'};

geocoder.geocode (request, function(response, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.fitBounds (new google.maps.LatLngBounds(endDe, endAte));
/* ... */
var pontos = new google.maps.MVCArray ();
pontos.push (endDe);
pontos.push (endAte);

var rect = new google.maps.Polyline ({
path: pontos,
map:map,
strokeWeight: 5,
strokeColor: 'blue',
visible: true
});
}
});
Após as inicializações de praxe para o ambiente do Maps, o código solicita a geocodificação do endereço da ABC71 (na verdade, sua latitude/longitude).
Em resposta à conclusão da geocodificação, isto é, assim que o mapa com o endereço solicitado está pronto, eu crio uma lista MVCArray e adiciono a ela os dois pontos que definem a reta desejada.

Em seguida, instancio a classe Polyline propriamente dita, fornecendo-lhe a lista de pontos. Também indico o mapa onde a linha será traçada (map), a espessura da linha em pixels (strokeWeight) e a cor dela (strokeColor). As cores podem ser informadas tanto pelo nome HTML quanto pela notação RGB hexadecimal.

Posso, por exemplo, demarcar um bairro inteiro com esse recurso? Sim, mas você terá que montar a lista de pontos o mais completa possível para que o desenho resultante tenha uma precisão adequada. O Polyline produz linhas abertas; para traçar linhas fechadas com uma quantidade arbitrária de pontos use a classe Polygon.

A função fitBounds, usada no início da resposta, apenas aplica um nível de zoom apropriado para garantir que ambos os endereços sejam exibidos num único quadro, sem que o usuário precise interagir com ele.

O código analisado produz o mapa a seguir:
Imagine agora o caso de uma pizzaria que queira divulgar num mapa o raio de ação onde ela faz entregas. O overlay produzido pela classe Circle permite dar destaque a uma área circular, dado um centro e um raio em metros. Veja o exemplo:
var endDe = new google.maps.LatLng(-23.566146,-46.652579);
var request = { location: endDe, region: 'BR'};

geocoder.geocode (request, function(response, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(endDe);
/* ... */
var circleOpts = ({
map: map,
center: endDe,
editable: false,
fillColor: 'yellow',
fillOpacity: 0.4,
radius: 3500,
strokeColor: '#0099ff',
strokeWeight: 4,
visible: true });
var circle = new google.maps.Circle (circleOpts);
}
});
Como no caso da linha, para o círculo também valem as propriedades que indicam o mapa, a cor do traço e sua espessura. Mas, ao invés de uma lista de pontos, informamos apenas o centro; no código anterior, usei o próprio endereço da ABC71 para isso. A definição do círculo fica completa com a propriedade radius - o raio, fornecido em metros; no exemplo, o raio terá 3500 metros (ou 3,5 Km).

Outra configuração disponível diz respeito ao preenchimento da área delimitada pelo círculo. A propriedade fillColor determina a cor do preenchimento enquanto a fillOpacity controla o grau de transparência, sendo que o valor 1 significa totalmente opaco (o mapa sob o círculo não é visto) e o valor 0 suspende o preenchimento.

A propriedade editable, quando ativa, permite ao usuário redimensionar o círculo. Eu a desliguei pois ela não faz sentido no contexto do exemplo. O resultado é o mapa exibido no quadro abaixo:

Os mesmos conceitos valem para a classe Rectangle. Além disso, é permitido trabalhar com vários overlays num mesmo mapa, se for necessário. Os exemplos publicados nesse post podem ser acessados respectivamente nos seguintes links : Overlay com Linha e Overlay com Círculo.

23 de novembro de 2012

Integrando o Outlook em aplicações Delphi - Parte II

No último post, eu mostrei os conceitos básicos envolvidos na integração do Outlook com aplicações Delphi. O exemplo apresentado lá abordou a manipulação dos contatos cadastrados no Outlook bem como a criação de novos contatos. Neste post eu abordo o aspecto mais utilizado da ferramenta, que é lidar com envio e recebimento de emails.

Enviar um email com o Outlook de dentro de um programa Delphi é uma operação relativamente simples. Assim como no caso dos contatos, o ponto de partida é objeto Outlook.Application. Aqui, no entanto, não é necessário trabalhar com Namespaces. Basta criar uma instância de MailItem (este é o tipo de objeto do Outlook que representa uma nova mensagem), fornecer-lhe informações relevantes para o envio e, então, efetivamente enviá-la. O código a seguir exemplifica esses passos:
procedure TForm1.btnEnviarClick(Sender: TObject);
var OutlookApp: TOutlookApplication;
email : MailItem;
begin
OutlookApp := TOutlookApplication.Create(Nil);

email := OutlookApp.CreateItem(olMailItem) As MailItem;
email.Subject := 'Envio automático';
email.BodyFormat := olFormatHTML;
email.HTMLBody := 'Este email é um <b>teste</b> para envio <b><span style="color:maroon;">automático</span></b>.';
email.Importance := olImportanceNormal;

email.Recipients.Add('balaiotecnologico@gmail.com');
if (email.Recipients.ResolveAll) then
email.Send
else begin
Application.MessageBox('Um ou mais destinatários não puderam ser resolvidos.'#13+
'Reveja a informação e tente novamente.'
, 'Alerta', MB_ICONWARNING);
email.Display(true);
end;

OutlookApp.Disconnect;
OutlookApp.Free;
end;
Veja que a criação da instância da mensagem é feita diretamente no objeto que representa a aplicação Outlook. A função CreateItem usada para esse fim é genérica e permite criar qualquer item dentro do Outlook. Assim, o valor olMailItem passado como parâmetro garante que o que está sendo criado é uma nova mensagem.

Após a criação, eu formato a mensagem fornecendo valores para propriedades relevantes como o assunto (Subject), a prioridade da mensagem (Importance), o texto dela (Body ou HTMLBody, dependendo do formato escolhido) e os destinários que a receberão (Recipients).

Opcionalmente, o método ResolveAll da lista de destinatários é chamado para verificar se os endereços incluídos são válidos. Em caso negativo, a própria tela de envio de email do Outlook é apresentada para que o usuário faça as correções necessárias antes de enviar o email manualmente.

Uma vez que a verificação foi feita com sucesso, a função Send é chamada para efetivamente fazer o envio. Por padrão, uma cópia da mensagem é armazenada na pasta Sent Items. Se não quiser guardar a cópia, use a propriedade DeleteAfterSubmit, ajustando-a para true. É possível também indicar outra pasta para guardar a cópia, modificando-se o valor da propriedade SaveSentMessageFolder.

Repare que não informei quem é o remetente da mensagem. Normalmente, o Outlook é configurado para se logar automaticamente quando a aplicação é executada, fazendo com que o remetente seja este usuário que fez o logon. É possível forçar outro logon por código, usando a função Logon de forma explícita e passando a ela as credenciais a serem utilizadas.

O código finaliza desconectando do Outlook e liberando a memória que esta sendo usada por ele.

Neste exemplo, passei o valor olFormatHTML na propriedade BodyFormat para permitir a inserção de código HTML diretamente em HTMLBody, o que flexibiliza a formatação da mensagem.

Embora eu não tenha tratado no código, é possível também incluir anexos no email. Um MailItem possui a propriedade Attachments para conter a lista de anexos. Antes do envio, podemos adicionar um ou mais anexos:
email.Attachments.Add('c:\ERP\abc71.jpg', EmptyParam, EmptyParam, EmptyParam);
O primeiro parâmetro é o caminho completo do arquivo a ser anexado. Os demais parâmetros são opcionais; passei EmptyParam a eles para que a função assuma valores internos padronizados para eles.

Para encerrar esse tópico, falo de um problema recorrente pra quem automatiza envio de email com o Outlook: a inclusão da assinatura padrão do usuário no corpo da mensagem. Da forma como foi exposto até aqui, apenas o texto incluído em HTMLBody será enviado, sem qualquer decoração extra que o usuário tenha configurado - como a assinatura ou um papel de carta. Isso acontece porque esses recursos não são inerentes ao MailItem mas sim ao editor associado a ele. Para acionar o editor, precisamos apenas invocar o método GetInspector. Um inspector é o responsável pela edição do item atual e, ao invocar o método, todo o ambiente para edição é criado, incluindo a formatação padrão para o item - neste caso, um email.

Isso preencherá o HTMLBody com um HTML completo, englobando a assinatura e outras formatações. Então, teremos que localizar a tag BODY desse HTML para acrescentar nosso texto personalizado no local correto sem perder a formatação padrão. O quadro abaixo mostra como obter esse efeito:
var { ... }
email : MailItem;
insp : Inspector;
idx: integer;
begin
{ ... }
insp := email.GetInspector;

idx := Pos ('<body', email.HTMLBody);
idx := PosEx ('>', email.HTMLBody, idx);
email.HTMLBody := MidStr (email.HTMLBody, 1, idx) +
'Este email é um <b>teste</b> para envio <b><span style="color:maroon;">automático</span></b>.' +
MidStr (email.HTMLBody, idx+1, Length(email.HTMLBody));

if (email.Recipients.ResolveAll) then
email.Send;
{...}
Nessa abordagem, apesar de o editor ser criado e sua configuração padrão ser respeitada, ele não é exibido para usuário. Se for necessário, chame o Display do MailItem para exibí-lo.

Comentei no post anterior mas não custa lembrar: todas as operações descritas neste post exigem que o Outlook esteja instalado no computador que for executá-las.