diff --git a/plugins/captcha/AUTHORS b/plugins/captcha/AUTHORS
new file mode 100644
index 0000000..8e3271f
--- /dev/null
+++ b/plugins/captcha/AUTHORS
@@ -0,0 +1,3 @@
+Silvio Clecio
+Luciano Souza
+Joao Morais
\ No newline at end of file
diff --git a/plugins/captcha/LICENSE b/plugins/captcha/LICENSE
new file mode 100644
index 0000000..23acdf7
--- /dev/null
+++ b/plugins/captcha/LICENSE
@@ -0,0 +1,28 @@
+Captcha plugin.
+
+Copyright (C) 2013 Silvio Clecio - silvioprog@gmail.com
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version with the following modification:
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent modules,and
+to copy and distribute the resulting executable under terms of your choice,
+provided that you also meet, for each linked independent module, the terms
+and conditions of the license of that module. An independent module is a
+module which is not derived from or based on this library. If you modify
+this library, you may extend this exception to your version of the library,
+but you are not obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\ No newline at end of file
diff --git a/plugins/captcha/README b/plugins/captcha/README
new file mode 100644
index 0000000..168f32f
--- /dev/null
+++ b/plugins/captcha/README
@@ -0,0 +1,19 @@
+Captcha plugin
+==============
+
+Nowadays, Pascal is fully immersed in web development world. Therefore, it faces the severe issue of spams.
+This plugin provides the handling of verification images, usually to block the free and automatic access in login pages.
+
+Installation
+============
+
+1. Open the package "captchapkg.lpk", in the dialog that opens, click in "Use >>" and "Add to Project";
+
+Steps to run this demo
+======================
+
+On Windows, copy the DLLs "freetype-6.dll" and "zlib1.dll" and the font "LiberationSerif-Regular.ttf" to your project folder.
+
+On Linux, copy the font "LiberationSerif-Regular.ttf" to your project folder.
+
+Enjoy!
\ No newline at end of file
diff --git a/plugins/captcha/demo/brokers.pas b/plugins/captcha/demo/brokers.pas
new file mode 100644
index 0000000..f5dcdc7
--- /dev/null
+++ b/plugins/captcha/demo/brokers.pas
@@ -0,0 +1,12 @@
+unit Brokers;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ BrookFCLCGIBroker;
+
+implementation
+
+end.
diff --git a/plugins/captcha/demo/cgi1.lpi b/plugins/captcha/demo/cgi1.lpi
new file mode 100644
index 0000000..7587bb7
--- /dev/null
+++ b/plugins/captcha/demo/cgi1.lpi
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/captcha/demo/cgi1.lpr b/plugins/captcha/demo/cgi1.lpr
new file mode 100644
index 0000000..d723ead
--- /dev/null
+++ b/plugins/captcha/demo/cgi1.lpr
@@ -0,0 +1,10 @@
+program cgi1;
+
+{$mode objfpc}{$H+}
+
+uses
+ BrookApplication, Brokers, test;
+
+begin
+ BrookApp.Run;
+end.
diff --git a/plugins/captcha/demo/test.pas b/plugins/captcha/demo/test.pas
new file mode 100644
index 0000000..8607638
--- /dev/null
+++ b/plugins/captcha/demo/test.pas
@@ -0,0 +1,69 @@
+unit test;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ BrookAction, Captcha, RUtils, Classes, SysUtils;
+
+type
+ TTest = class(TBrookAction)
+ public
+ procedure Get; override;
+ procedure Post; override;
+ end;
+
+const
+ FORM =
+ ''+lf+
+ ''+lf+
+ '
'+lf+
+ ' '+lf+
+ ' '+lf+
+ ''+lf+
+ ''+lf+
+ ''+lf+
+ ' '+lf+
+ ''+lf+
+ '';
+
+implementation
+
+uses
+ FPWritePNG;
+
+procedure TTest.Get;
+var
+ VImage: TMemoryImage;
+ VStream: TMemoryStream;
+begin
+ if not TCaptcha.FontExists(ftLiberationSerifRegularTTF) then
+ Exit;
+ VImage := TMemoryImage.Create;
+ VStream := TMemoryStream.Create;
+ try
+ SetCookie('captcha', TCaptcha.Generate(VStream));
+ VStream.Seek(0, 0);
+ Write(FORM, [StreamToBase64(VStream)]);
+ finally
+ VStream.Free;
+ VImage.Free;
+ end;
+end;
+
+procedure TTest.Post;
+begin
+ if SameText(Fields.Values['captcha'], GetCookie('captcha')) then
+ Write('OK')
+ else
+ Write('Fail');
+end;
+
+initialization
+ TTest.Register('*');
+
+end.
diff --git a/plugins/captcha/pkg/captchapkg.lpk b/plugins/captcha/pkg/captchapkg.lpk
new file mode 100644
index 0000000..3e92c8d
--- /dev/null
+++ b/plugins/captcha/pkg/captchapkg.lpk
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/captcha/src/captcha.pas b/plugins/captcha/src/captcha.pas
new file mode 100644
index 0000000..bb67909
--- /dev/null
+++ b/plugins/captcha/src/captcha.pas
@@ -0,0 +1,183 @@
+(*
+ Captcha plugin.
+ Copyright (C) 2012-2014 Silvio Clecio.
+
+ Please see the LICENSE file.
+*)
+
+unit Captcha;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ FPCanvas, FPImage, FPImgCanv, FTFont, Classes, SysUtils;
+
+const
+ colDkTeal: TFPColor = (Red: $0000; Green: $2000; Blue: $5000;
+ Alpha: AlphaOpaque);
+ ftLiberationSerifRegularTTF = 'LiberationSerif-Regular.ttf';
+
+type
+ TCaptchaType = (ctNoise, ctLine);
+
+ { TMemoryImage }
+
+ TMemoryImage = class(TFPMemoryImage)
+ public
+ constructor Create; overload;
+ end;
+
+ { TCaptcha }
+
+ TCaptcha = class
+ public
+ class function FontExists(const AFileName: TFileName): Boolean;
+ class function Generate(AImage: TMemoryImage;
+ const AFontColor: TFPColor; const AFontName: ShortString =
+ ftLiberationSerifRegularTTF; const AFontSize: Byte = 18;
+ const AEasyRead: Byte = 3; const ABackground: Boolean = True;
+ const ACaptchaType: TCaptchaType = ctLine): string; overload;
+ class function Generate(AImage: TMemoryImage;
+ const ACaptchaType: TCaptchaType = ctLine): string; overload;
+ class function Generate(AStream: TStream;
+ const ACaptchaType: TCaptchaType = ctLine): string; overload;
+ end;
+
+implementation
+
+{ TMemoryImage }
+
+constructor TMemoryImage.Create;
+begin
+ inherited Create(100, 100);
+end;
+
+{ TCaptcha }
+
+class function TCaptcha.FontExists(const AFileName: TFileName): Boolean;
+{$IFDEF UNIX}
+const
+ VFontPath = '/usr/share/fonts';
+{$ENDIF}
+begin
+ Result := FileExists(AFileName) or
+{$IFDEF UNIX}
+ (FileExists(IncludeTrailingPathDelimiter(GetEnvironmentVariable('HOME')) +
+ '.fonts/' + AFileName)) or
+ (FileExists(VFontPath + AFileName)) or
+ (FileExists(VFontPath + '/truetype/' + AFileName)) or
+ (FileExists(VFontPath + '/truetype/freefont/')) ;
+{$ENDIF}
+{$IFDEF MSWINDOWS}
+ FileExists(IncludeTrailingPathDelimiter(GetEnvironmentVariable('windir')) +
+ 'Fonts' + DirectorySeparator + AFileName);
+{$ENDIF}
+end;
+
+{$WARNINGS OFF}
+class function TCaptcha.Generate(AImage: TMemoryImage;
+ const AFontColor: TFPColor; const AFontName: ShortString;
+ const AFontSize: Byte; const AEasyRead: Byte; const ABackground: Boolean;
+ const ACaptchaType: TCaptchaType): string;
+
+ function _Min(A, B: Integer): Integer;
+ begin
+ if A < B then
+ Result := A
+ else
+ Result := B;
+ end;
+
+ function _RandomRange(const AFrom, ATo: Integer): Integer;
+ begin
+ Result := Random(Abs(AFrom - ATo)) + _Min(ATo, AFrom);
+ end;
+
+const
+ NUMBERS = '0123456789';
+ ALPHA_NUMERIC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + NUMBERS;
+var
+ I: Integer;
+ VFont: TFreeTypeFont;
+ VCanvas: TFPImageCanvas;
+begin
+ VFont := TFreeTypeFont.Create;
+ VCanvas := TFPImageCanvas.Create(AImage);
+ AImage.SetSize(80, 20);
+ try
+ VFont.Name := AFontName;
+ VFont.Size := AFontSize;
+ VFont.FPColor := AFontColor;
+ VCanvas.Font := VFont;
+ if ABackground then
+ begin
+ VCanvas.Brush.FPColor := colWhite;
+ VCanvas.Brush.Style := bsSolid;
+ VCanvas.FillRect(0, 0, VCanvas.Width, VCanvas.Height);
+ end;
+ VCanvas.Clear;
+ VCanvas.Pen.FPColor := VFont.FPColor;
+ if ACaptchaType = ctNoise then
+ begin
+ for I := 0 to (AImage.Width * AImage.Height) div AEasyRead do
+ VCanvas.EllipseC(_RandomRange(0, AImage.Width),
+ _RandomRange(0, AImage.Height), 0, 0);
+ for I := 1 to 6 do
+ Result += Copy(NUMBERS, _RandomRange(0, Length(NUMBERS) - 1), 1);
+ VCanvas.TextOut((VCanvas.Width div 2) -
+ (VCanvas.GetTextWidth(Result) div 2),
+ (VCanvas.Height div 2) + (VCanvas.GetTextHeight(Result) div 2),
+ Result);
+ end
+ else
+ begin
+ for I := 0 to 3 do
+ Result += ALPHA_NUMERIC[Random(Length(ALPHA_NUMERIC) - 1) + 1];
+ for I := 0 to 3 do
+ begin
+ VCanvas.Font.Size := _RandomRange(4, 12) + 6;
+ VCanvas.TextOut(I * 22, 16, Result[I + 1]);
+ end;
+ for I := 0 to AEasyRead do
+ begin
+ VCanvas.MoveTo(Random(AImage.Width), 0);
+ VCanvas.LineTo(Random(AImage.Width), AImage.Height);
+ end;
+ end;
+ finally
+ VFont.Free;
+ VCanvas.Free;
+ end;
+end;
+{$WARNINGS ON}
+
+class function TCaptcha.Generate(AImage: TMemoryImage;
+ const ACaptchaType: TCaptchaType): string;
+begin
+ Result := Generate(AImage, colDkTeal, ftLiberationSerifRegularTTF, 18, 3,
+ True, ACaptchaType);
+end;
+
+class function TCaptcha.Generate(AStream: TStream;
+ const ACaptchaType: TCaptchaType): string;
+var
+ VImage: TMemoryImage;
+ VWriter: TFPCustomImageWriter;
+begin
+ VImage := TMemoryImage.Create;
+ VWriter := ImageHandlers.ImageWriter[ImageHandlers.TypeNames[0]].Create;
+ try
+ Result := Generate(VImage, ACaptchaType);
+ VImage.SaveToStream(AStream, VWriter);
+ finally
+ VImage.Free;
+ VWriter.Free;
+ end;
+end;
+
+initialization
+ Randomize;
+
+end.