Home > Delphi stuff, Software > Twitter library for Delphi

Twitter library for Delphi

February 27th, 2011 Leave a comment Go to comments

2013 fix/update: http://code.google.com/p/delphi-twitter-library/

Edit: As of December 2012 Twitter api is using GZip in every callback, so you’ll have to enable content encoding before every Get/Post call, and then load the result from a gzipped stream in the RequestDone procs.

Edit June 2012: This twitter library is now deprecated and will no longer be updated. I’ve rewritten it as a generic OAuth lib to use with both Twitter and Imgur (and any other OAuth 1.0 services) for a closed source project.

This is my take on Open Auth and Twitter for Delphi. I recently had to look into it to update a twitter plugin for my Mal Upater application, so I made this small library along with a test application TwitMee. There is barely nothing at all for Delphi, and the little
I found was overcomplicated and didn’t work with Unicode (f.e. japanese symbols etc) (my library does).

I’ve been asked by a few people to make it open source, so here’s the code, use it freely as long you comply with the GPL v3 license.

Requirements: one of the latest versions of Delphi which includes Unicode. (probably easy to adapt using Jedi’s jcl implementation
for unicode strings as well).

Download

TwitterLib - 1690 downloads

Twitter object unit:

{
You can contact me at: http://eden.fm

License Version: GPL v3

The contents of this file are subject to the GPL License Version
3 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.gnu.org/licenses/gpl.html

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

You may use the code freely for freeware and commercial applications, as long
you keep a notice the software is using my library, and the original source
of my code isn't modified.

TwitterLib for Delphi v0.1. Developed by http://eden.fm

Usage: see usage.pas for details.

3rd party: I'm using ICS' overbyte winsock library, which you can get
at www.overbyte.be
After you install that, you need to overwrite (or place in your app folder)
the file "OverbyteIcsHttpProt.pas" which is included in the rar where you
obtained this file. It's a slightly modified version of the ICS THttpCli
component to ease a bit the header modifications before a call.

- b64asm: this is a very fast implementation I found to encode into base64
I was originally using madshi's madCrypt unit, which was actually as fast,
but this should be easier to distribute.

}

unit TwitterLib;

interface

Uses Windows, SysUtils, Classes, StdCtrls,

b64ASM, OverbyteIcsSha1, OverbyteIcsHttpProt;

Const
RequestTokenURL = 'http://api.twitter.com/oauth/request_token';
RequestAccessURL = 'http://api.twitter.com/oauth/access_token';
RequestTwitURL = 'http://api.twitter.com/1/statuses/update.xml';

shell32 = 'shell32.dll';

{$EXTERNALSYM ShellExecute}
function ShellExecute(hWnd: hWnd; Operation, FileName, Parameters,
Directory: PWideChar; ShowCmd: Integer): HINST; stdcall;

Type
TwitterRequests = (trDummy, trRequestToken, trRequestAccess, trTwit);

Type
TwitterCli = class(TObject)
private
FOnReqDone: TNotifyEvent;
FOnBeforeSocketCall: TNotifyEvent;
// use this to set socket proxy option, since sockets are created/destroyed on demand
procedure TriggerReqDone; virtual;
procedure TriggerBeforeSocketCall; virtual;

procedure RecreateSocket;

// CallbackProc: pointer;
// VCL handlers
procedure HTTPClientDocEnd(Sender: TObject);
procedure HTTPClientHeaderEnd(Sender: TObject);
procedure HTTPClientRequestDone(Sender: TObject; RqType: THttpRequest;
ErrCode: Word);
procedure HTTPClientBeforeHeaderSend(Sender: TObject; const Method: string;
Headers: TStrings);

procedure BuildSignature;
procedure GetTimeStamp;
procedure GetNonce;
procedure GenerateBaseURL(Method, url: string);
procedure ParseTokenandTokenSecret(rawResult: string);
procedure ParseAccessData(rawResult: string);

public
ConsumerKey: string;
ConsumerSecret: string;

OAuthToken: string;
OAuthTokenSecret: string;
AccessToken: string;
AccessTokenSecret: string;
AccessUserID: string;
AccessScreenName: string;

URLRequestToken: string;
URLRequestAccess: string;
URLTwit: string;
SignBase: string;
TStamp: string;
Nonce: string;
Signature: string;
Postvars: Ansistring;
AuthHeader: string;
HTTPClient: THttpCli;
RefURL: string;
ResultStrings: TStringList;
LastReq: TwitterRequests;
DebugMode: Boolean;
DebugMemo: TMemo;
LastHttpStatus: Integer;
AccessPIN: String;
SendStatus: String;

Constructor Create(CKey, CSecret: string); // virtual;
Destructor Destroy; override;

procedure RequestToken; // socket call
procedure RequestAccess; // socket call
procedure SendTwit(twit: string); // socket call
procedure RequestPIN; // call browser

function RequestPinURL: string;
procedure SetStoredLogin(AToken, ATokenSecret: string);
published
property OnReqDone: TNotifyEvent read FOnReqDone write FOnReqDone;
property OnBeforeSocketCall: TNotifyEvent read FOnBeforeSocketCall
write FOnBeforeSocketCall;
end;

function UrlEncode2(const S: String): String;
function UrlEncodeExceptUnicode(const S: String): String;
function DateTimeToUnix(DelphiTime: TDateTime): Int64;
function urlEncodeRFC3986(url: string): string;
function HasUnicode(src: string): Boolean;
function BuildHexedUtf8String(src: string): string;

implementation

function ShellExecute; external shell32 name 'ShellExecuteW';

function BuildHexedUtf8String(src: string): string;
Var
ut: utf8string;
a: Integer;
BinarySize: Integer;
InputString: utf8string;
StringAsBytes: array of Byte;
begin
Result := '';
for a := 1 to length(src) do
begin
if Ord(src[a]) < 255 then
begin
if src[a] = ' ' then
Result := Result + '%2520'
else
Result := Result + UrlEncode2(src[a]);
end
else
begin
ut := src[a];
BinarySize := 3; // (Length(InputString) + 1) * SizeOf(Char);
SetLength(StringAsBytes, BinarySize);
Move(ut[1], StringAsBytes[0], BinarySize);
Result := Result + '%25' + IntToHex(StringAsBytes[0], 2);
Result := Result + '%25' + IntToHex(StringAsBytes[1], 2);
Result := Result + '%25' + IntToHex(StringAsBytes[2], 2);
end;
end;
end;

function HasUnicode(src: string): Boolean;
Var
a: Integer;
begin
Result := False;
for a := 1 to length(src) do
if Ord(src[a]) > 255 then
Exit(True);
end;

function DateTimeToUnix(DelphiTime: TDateTime): Int64;
begin
Result := Round((DelphiTime - 25569) * 86400);
end;

function UrlEncode2(const S: String): String;
var
I: Integer;
Ch: Char;
begin
Result := '';
for I := 1 to length(S) do
begin
Ch := S[I];
if ((Ch >= '0') and (Ch <= '9')) or ((Ch >= 'a') and (Ch <= 'z')) or
((Ch >= 'A') and (Ch <= 'Z')) or (Ch = '.') or (Ch = '-') or (Ch = '_') or
(Ch = '~') then
Result := Result + Ch
else
begin
// if HasUnicode(Ch) then Result := Result + BuildHexedUtf8String(Ch)
{ else } Result := Result + '%' + IntToHex(Ord(Ch), 2);
end;
end;
end;

function UrlEncodeExceptUnicode(const S: String): String;
var
I: Integer;
Ch: Char;
begin
Result := '';
for I := 1 to length(S) do
begin
Ch := S[I];
if ((Ch >= '0') and (Ch <= '9')) or ((Ch >= 'a') and (Ch <= 'z')) or
((Ch >= 'A') and (Ch <= 'Z')) or (Ch = '.') or (Ch = '-') or (Ch = '_') or
(Ch = '~') or HasUnicode(Ch) then
Result := Result + Ch
else
Result := Result + '%' + IntToHex(Ord(Ch), 2);
end;
end;

function urlEncodeRFC3986(url: string): string;
var
URL1: string;
begin
URL1 := UrlEncode2(url);
URL1 := StringReplace(URL1, '+', ' ', [rfReplaceAll, rfIgnoreCase]);
Result := URL1;
end;

Constructor TwitterCli.Create(CKey, CSecret: string);
begin
inherited Create;

ConsumerKey := CKey;
ConsumerSecret := CSecret;
DebugMode := False;

URLRequestToken := RequestTokenURL;
URLRequestAccess := RequestAccessURL;
URLTwit := RequestTwitURL;

ResultStrings := TStringList.Create;
end;

Destructor TwitterCli.Destroy;
begin
ResultStrings.Free;
inherited Destroy;
end;

procedure TwitterCli.BuildSignature;
Var
SignKey: string;
begin
SignKey := UrlEncode2(ConsumerSecret) + '&' + UrlEncode2(OAuthTokenSecret);
Signature := { madCrypt.Encode } b64ASM.Base64Encode
(HMAC_SHA1_EX(SignBase, SignKey));
if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Build Signature -');
Lines.Add('SignKey=' + SignKey);
Lines.Add('Signature=' + Signature);
Lines.Add('----------------------------------');
end;
end;

procedure TwitterCli.GetTimeStamp;
begin
TStamp := IntToStr(DateTimeToUnix(Now));
end;

procedure TwitterCli.GetNonce;
Var
a: Integer;
begin
Nonce := '';
for a := 1 to 20 do
Nonce := Nonce + Chr(Random(26) + 65);
end;

procedure TwitterCli.GenerateBaseURL(Method, url: string);
Var
ver, tok, cbak: string;
begin
GetNonce;
GetTimeStamp;
if AccessPIN <> '' then
ver := 'oauth_verifier=' + AccessPIN + '&'
else
ver := '';
// if OAuthToken <> '' then tok := 'oauth_token=' + OAuthToken + '&' else tok := '';

tok := 'oauth_token=' + OAuthToken + '&';
if LastReq <> trTwit then
cbak := 'oauth_callback=oob&';

SignBase := Method + '&' + UrlEncode2(url) + '&' +
UrlEncode2(cbak + 'oauth_consumer_key=' + ConsumerKey + '&' + 'oauth_nonce='
+ Nonce + '&' + 'oauth_signature_method=HMAC-SHA1' + '&' +
'oauth_timestamp=' + TStamp + '&' + tok + ver // access PIN if any
+ 'oauth_version=1.0');

if SendStatus <> '' then
SignBase := SignBase + UrlEncode2('&status=') + BuildHexedUtf8String
(SendStatus);

if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Generate Base URL -');
Lines.Add('base=' + SignBase);
Lines.Add('----------------------------------');
end;
end;

procedure TwitterCli.RequestToken;
begin

LastReq := trRequestToken;

OAuthToken := '';
OAuthTokenSecret := '';
AccessToken := '';
AccessTokenSecret := '';
AccessPIN := '';

GenerateBaseURL('GET', URLRequestToken);
BuildSignature;
Postvars := 'oauth_consumer_key' + '=' + ConsumerKey + '&' +
'oauth_signature_method' + '=' + 'HMAC-SHA1' + '&' + 'oauth_signature' + '='
+ UrlEncode2(Signature) + '' + '&' + 'oauth_timestamp' + '=' + TStamp + '&'
+ 'oauth_nonce' + '=' + Nonce + '&' + 'oauth_token' + '=' + OAuthToken + '&'
+ 'oauth_callback' + '=' + 'oob' + '&' + 'oauth_version' + '=' + '1.0';

RecreateSocket;

HTTPClient.ExtraSendHeader := 'Authorization: OAuth oauth_nonce="' + Nonce +
'", oauth_callback="oob", oauth_token="' + OAuthToken +
'", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + TStamp +
'", oauth_consumer_key="' + ConsumerKey + '", oauth_signature="' +
UrlEncode2(Signature) + '", oauth_version="1.0"';

With HTTPClient do
begin
Reference := RefURL;
RcvdStream := TMemoryStream.Create;
// SendStream := TMemoryStream.Create;
// SendStream.Write(postvars[1], Length(postvars));
// SendStream.Seek(0, soFromBeginning);
Accept := '*/*';
url := URLRequestToken; // + '?' + postvars;
ResultStrings.Clear;

if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Request Token Start -');
Lines.Add('postvars=' + Postvars);
Lines.Add('url=' + url);
Lines.Add('----------------------------------');
end;

try
GetAsync;
except
on E: Exception do
begin
RcvdStream.Destroy;
RcvdStream := nil;
// SendStream.Destroy; SendStream := nil;
ResultStrings.Text := 'ERROR ' + E.Message;
LastHttpStatus := HTTPClient.StatusCode;
TriggerReqDone;
FreeAndNil(HTTPClient);
Exit;
end;
end; // try
end; // with
end;

procedure TwitterCli.RequestAccess;
begin

LastReq := trRequestAccess;

GenerateBaseURL('GET', URLRequestAccess);
BuildSignature;
Postvars := 'oauth_consumer_key' + '=' + ConsumerKey + '&' + 'oauth_nonce' +
'=' + Nonce + '&' + 'oauth_signature_method' + '=' + 'HMAC-SHA1' + '&' +
'oauth_signature' + '=' + UrlEncode2(Signature) + '' + '&' +
'oauth_timestamp' + '=' + TStamp + '&' + 'oauth_token' + '=' + OAuthToken +
'&' + 'oauth_callback' + '=' + 'oob' + '&' + 'oauth_verifier' + '=' +
AccessPIN + '&' + 'oauth_version' + '=' + '1.0'; // + '&' +
// 'oauth_callback' + '=' + 'oob' + '&' +

RecreateSocket;

HTTPClient.ExtraSendHeader := 'Authorization: OAuth oauth_nonce="' + Nonce +
'", oauth_callback="oob", oauth_token="' + OAuthToken +
'", oauth_verifier="' + AccessPIN +
'", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + TStamp +
'", oauth_consumer_key="' + ConsumerKey + '", oauth_signature="' +
UrlEncode2(Signature) + '", oauth_version="1.0"';

With HTTPClient do
begin
Reference := RefURL;
RcvdStream := TMemoryStream.Create;
url := URLRequestAccess; // + '?' + postvars;
ResultStrings.Clear;

if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Request Access Start -');
Lines.Add('postvars=' + Postvars);
Lines.Add('url=' + url);
Lines.Add('----------------------------------');
end;

try
GetAsync;
except
on E: Exception do
begin
RcvdStream.Destroy;
RcvdStream := nil;
ResultStrings.Text := 'ERROR ' + E.Message;
LastHttpStatus := HTTPClient.StatusCode;
FreeAndNil(HTTPClient);
TriggerReqDone;
Exit;
end;
end; // try
end; // with
end;

procedure TwitterCli.SendTwit(twit: string);
begin
// showmessage(twit);
// twit := URLEncode2(twit);

// fix issue, # + unicode fails

LastReq := trTwit;
if HasUnicode(twit) then
begin
twit := UrlEncodeExceptUnicode(twit);
// StringReplace(twit,'#','%2523',[rfReplaceAll]);
SendStatus := twit;
end
else
SendStatus := UrlEncode2(utf8Encode(twit));
AccessPIN := '';

GenerateBaseURL('POST', URLTwit);
BuildSignature;
Postvars := 'oauth_consumer_key' + '=' + ConsumerKey + '&' + 'oauth_nonce' +
'=' + Nonce + '&' + 'oauth_signature_method' + '=' + 'HMAC-SHA1' + '&' +
'oauth_signature' + '=' + UrlEncode2(Signature) + '' + '&' +
'oauth_timestamp' + '=' + TStamp + '&' + 'oauth_token' + '=' + AccessToken +
'&' + 'oauth_callback' + '=' + 'oob' + '&' + 'oauth_version' + '=' + '1.0';

if HasUnicode(twit) then
Postvars := 'status=' + { urlencode2 } ((utf8Encode(twit)))
else
Postvars := 'status=' + UrlEncode2(twit);

SendStatus := '';

RecreateSocket;

HTTPClient.ExtraSendHeader := 'Authorization: OAuth ' + 'oauth_consumer_key="'
+ ConsumerKey + '", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' +
TStamp + '", oauth_nonce="' + Nonce +
'", oauth_version="1.0", oauth_token="' + AccessToken +
'", oauth_signature="' + UrlEncode2(Signature) + '"';

With HTTPClient do
begin
Reference := RefURL;
RcvdStream := TMemoryStream.Create;
SendStream := TMemoryStream.Create;
SendStream.Write(Postvars[1], length(Postvars));
SendStream.Seek(0, soFromBeginning);
url := URLTwit; // + '?' + postvars;
ResultStrings.Clear;

if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Request twit Start -');
Lines.Add('postvars=' + Postvars);
Lines.Add('url=' + url);
Lines.Add('----------------------------------');
end;

try
PostAsync;
except
on E: Exception do
begin
RcvdStream.Destroy;
RcvdStream := nil;
SendStream.Destroy;
SendStream := nil;
ResultStrings.Text := 'ERROR ' + E.Message;
LastHttpStatus := HTTPClient.StatusCode;
FreeAndNil(HTTPClient);
TriggerReqDone;
Exit;
end;
end; // try
end; // with
end;

procedure TwitterCli.TriggerReqDone;
begin
if Assigned(FOnReqDone) then
FOnReqDone(Self);
end;

procedure TwitterCli.TriggerBeforeSocketCall;
begin
if Assigned(FOnBeforeSocketCall) then
FOnBeforeSocketCall(Self);
end;

procedure TwitterCli.HTTPClientDocEnd(Sender: TObject);
begin
//
end;

procedure TwitterCli.HTTPClientBeforeHeaderSend(Sender: TObject;
const Method: string; Headers: TStrings);
begin
if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Socket Before Header Send -');
Lines.Add(Headers.Text);
Lines.Add('----------------------------------');
end;
end;

procedure TwitterCli.HTTPClientHeaderEnd(Sender: TObject);
begin
if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Socket Header End -');
Lines.Add(HTTPClient.RcvdHeader.Text);
Lines.Add('----------------------------------');
end;
end;

procedure TwitterCli.HTTPClientRequestDone(Sender: TObject;
RqType: THttpRequest; ErrCode: Word);
Label CleanUp;
begin
if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Request Done Socket DocEnd -');
Lines.Add('result=' + ResultStrings.Text);
Lines.Add('status code=' + IntToStr(HTTPClient.StatusCode));
Lines.Add('headers=' + HTTPClient.RcvdHeader.Text);
Lines.Add('----------------------------------');
end;

if (RqType = httpGET) or (RqType = httpPOST) then
begin
if (ErrCode <> 0) or (HTTPClient.StatusCode <> 200) then
Goto CleanUp;
end
else
Exit;

try
HTTPClient.RcvdStream.WriteBuffer(#0' ', 1);
HTTPClient.RcvdStream.Position := 0;
ResultStrings.LoadFromStream(HTTPClient.RcvdStream);
finally
end;

LastHttpStatus := HTTPClient.StatusCode;

if (LastReq = trRequestToken) and (LastHttpStatus = 200) then
ParseTokenandTokenSecret(ResultStrings.Text);
if (LastReq = trRequestAccess) and (LastHttpStatus = 200) then
ParseAccessData(ResultStrings.Text);

CleanUp:

HTTPClient.RcvdStream.Destroy;
HTTPClient.RcvdStream := nil;
if LastReq = trTwit then
begin
HTTPClient.SendStream.Destroy;
HTTPClient.SendStream := nil;
end;
FreeAndNil(HTTPClient);

TriggerReqDone;

end;

procedure TwitterCli.RecreateSocket;
begin
HTTPClient := THttpCli.Create(nil);
With HTTPClient do
begin
OnDocEnd := HTTPClientDocEnd;
OnHeaderEnd := HTTPClientHeaderEnd;
OnRequestDone := HTTPClientRequestDone;
OnBeforeHeaderSend := HTTPClientBeforeHeaderSend;
TriggerBeforeSocketCall;
end;
end;

procedure TwitterCli.ParseTokenandTokenSecret(rawResult: string);
begin
// parse tokens after request token
if Pos('oauth_callback_confirmed=true', rawResult) = 0 then
begin
LastHttpStatus := 0;
Exit;
end;

try
Delete(rawResult, 1, Pos('=', rawResult));
OAuthToken := Copy(rawResult, 1, Pos('&oauth_token_secret=',
rawResult) - 1);
Delete(rawResult, 1, Pos('=', rawResult));
OAuthTokenSecret := Copy(rawResult, 1, Pos('&oauth_callback_confirmed=true',
rawResult) - 1);
except
LastHttpStatus := 0;
end;

if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Parse Token and TokenSecret -');
Lines.Add('Token=' + OAuthToken);
Lines.Add('TokenSecret=' + OAuthTokenSecret);
Lines.Add('----------------------------------');
end;

end;

procedure TwitterCli.RequestPIN;
begin
ShellExecute(0, nil, PChar('https://twitter.com/oauth/authorize?oauth_token='
+ OAuthToken), '', '', SW_SHOWNORMAL);
end;

function TwitterCli.RequestPinURL;
begin
Result := 'https://twitter.com/oauth/authorize?oauth_token=' + OAuthToken;
end;

procedure TwitterCli.ParseAccessData(rawResult: string);
begin
// parse tokens after request acccess
if Pos('user_id', rawResult) = 0 then
begin
LastHttpStatus := 0;
Exit;
end;

try
Delete(rawResult, 1, Pos('=', rawResult));
AccessToken := Copy(rawResult, 1, Pos('&oauth_token_secret=',
rawResult) - 1);
Delete(rawResult, 1, Pos('=', rawResult));
AccessTokenSecret := Copy(rawResult, 1, Pos('&user_id=', rawResult) - 1);
Delete(rawResult, 1, Pos('=', rawResult));
AccessUserID := Copy(rawResult, 1, Pos('&screen_name=', rawResult) - 1);
Delete(rawResult, 1, Pos('=', rawResult));
AccessScreenName := rawResult;

OAuthToken := AccessToken;
OAuthTokenSecret := AccessTokenSecret;
except
LastHttpStatus := 0;
end;

if DebugMode then
if Assigned(DebugMemo) then
with TMemo(DebugMemo) do
begin
Lines.Add('- Parse Access Data -');
Lines.Add('AccessToken=' + AccessToken);
Lines.Add('AccessTokenSecret=' + AccessTokenSecret);
Lines.Add('AccessUserID=' + AccessUserID);
Lines.Add('AccessScreenName=' + AccessScreenName);
Lines.Add('----------------------------------');
end;

end;

procedure TwitterCli.SetStoredLogin(AToken: string; ATokenSecret: string);
begin
AccessToken := AToken;
AccessTokenSecret := ATokenSecret;
OAuthToken := AccessToken;
OAuthTokenSecret := AccessTokenSecret;
end;

end.

usage

// start by defining and creating the twitter object:

Var
Twit: TwitterCli;

Twit := TwitterCli.Create(TKey, TSecret);
with Twit do
begin
// You can specify a TMemo here for debugging purposes, which will output relevant
// data sent and received to twitter.
// DebugMode := True;
// DebugMemo := Memo1;
OnReqDone := TwitterCallBackProc;
RefURL := 'http://eden.fm';
end;

// TwitterCallBackProc is a simple method that's called after each request:
procedure TTwitMeMain.TwitterCallBackProc(Sender: TObject);
// TKey and TSecret are your app key and secret you get from Twitter after
// you register your app with them

// you can also specify a callback for TriggerBeforeSocketCall
// which will trigger just before a socket call. Here you can alter
// the socket to specify a proxy by accessing Twit.HTTPClient
// (as per ICS THttpCli properties)

// Next we need to request a token from Twitter:
// If you had already done this step before you can skip it, look at the
// end of this doc for details

Twit.RequestToken;

// Right after the call, control is given back to your application, since the
// call is asynchronous (non-blocking). the callback proc will be called after

// after we get the initial token from twitter, we need to send the user to
// twitter.com so they will login and get a PIN code to enter in your app

Twit.RequestPIN;
// you could also use Twit.RequestPinURL
// to get the URL in a string if you wish to copy it to the user in the
// clipboard or any other means, in case your app fails to launch the URL
// in the browser

// once done, the user has to give the PIN to us, in an edit box for example,
// then we tell the library the pin and request the final access tokens:

Twit.AccessPIN := Edit1.Text;
Twit.RequestAccess;

// our callback proc will be called once again and we are ready to send
// messages to twitter

// always check Twit.LastHttpStatus in the callback proc, if not 200 then
// something went wrong. You can check the variables ResultStrings.Text
// and LastHttpStatus for details on what went wrong

// now we can send a message with

Twit.SendTwit('test message');

// you can also use unicode here, like Japanese kanjis
// tested also with problematic symbols like # $ ! ' & etc

// * Note about access request: after you complete the acess steps,
// you can store these 2 string variables:
//
// Twit.AccessToken
// Twit.AccessTokenSecret

// and simply do: SetStoredLogin(a,b);
// after creating the twitter object (a and b being those 2 vars we stored
// and your app is ready to send without any previous steps

// And that's it, pretty simple. Note that this is a very simple implementation
// and we should check for other status codes from Twitter. I will be updating
// the library to fully implement the entire API eventually.

// a little more help. this is what my callback proc on TwitMee looks like:

procedure TTwitMeMain.TwitterCallBackProc(Sender: TObject);
begin
if Twit.LastHttpStatus <> 200 then
begin
Label1.Font.Color := clRed;
Label1.Caption := 'Error communicating with Twitter.';
Exit;
end;

if Twit.LastReq = trRequestToken then
begin
FlatEdit1.Text := 'Enter PIN here and click on Send button';
Twit.RequestPIN;
Exit;
end;
if Twit.LastReq = trRequestAccess then
begin
Label1.Font.Color := clWhite;
Label1.Caption := 'Ready to send.';
Authenticated := True;
FlatEdit1.Text := '';
SaveSettings;
Exit;
end;
if Twit.LastReq = trTwit then
begin
FlatEdit1.Text := '';
Label1.Caption := 'Message sent.';
Exit;
end;
end;
Categories: Delphi stuff, Software Tags:
  • http://www.motobutique.com.br Levi fernandes

    Hello
    Please could you send me the source of the “TwitMee – 0:22″ as an example of using the “Delphi library for Twitter”?

    If possible, please send to “levifernandes@ig.com.br.”

    Thank you.

  • brian -

    sent :)

  • Purrpurrpurr11

    Hi! Nice Stuff. I want to see TwitMee sources or another example for this lib. Of course if possible. Please sent to “purrpurrpurr11 at gmail.com”. Thx. =)

  • http://www.imperiousseo.com SEO athens

    this is superb blog and i got a lot from this blog. thanks a lot form sharing this useful stuffs with us.

  • Steve

    Hello,
    I’ve spent a fair while trying to get your code to work in Delphi6.
    Unfortunately I’m still getting ‘Status: 401 Unauthorized’ errors’.
    I’m nearly there but am now stuck.
    Would it be possible for you to send me the source for TwitMee V0.22 so I can see where I’m going wrong.
    My email is ‘twitter at play-time.demon.co.uk’
    Many Thanks in advance 

  • brian -

    Hi, it was made for Unicode Delphi, it won’t work as it is for 6 without some changes. I’ll send you the little app source anyway :)

  • Steve

    Many thanks for the source brian,

    I was able to get it working in Delphi6 (and with Unicode too I think).  I’m using the TntComponents for Unicode.
    Great work and thanks for sharing your skills.
    If you are interested I’ll let you know when my app. is released.

  • Victor

    hi brian,
     
    This is a nice work you have done:)
    Unfortunately, I am having difficulties in making the library work with a test sample i built with delphi 2010. 
    If it is possible, I would love as well to receive the source code for the TwitMee 0.22. My email is victorvicente at netcabo.pt
    Thanks a lot!

    Victor

  • brian -

    sent

  • Victor

    Thanks you very much for the fast reply!

  • http://twitter.com/madman_42 Adam Russell

    Hi brian, thanks for posting this code.  I’ve been comparing this code to other delphi twitter libraries and am still a bit unclear on how to make it work.  As below it would be great to get the source to the latest TwitMee app so I could see where I was going wrong.  please send to adamr99 at gmail.com

    thanks in advance.

    regards,
    adam

  • http://twitter.com/madman_42 Adam Russell

    Hi brian, also the rar that I downloaded had only the TwitterLib.pas file, and didn’t include the two other files you mention:

    OverbyteIcsHttpProt.pas

    useage.pas

    could you also please send these through to adamr99 at gmail.com

    thanks and regards,
    adam

  • Jane

    Dear brian, The rar that I downloaded had only the TwitterLib.pas file, seems it didn’t include the two other files you used:

    OverbyteIcsHttpProt.pas
    OverbyteIcsSha1.pas
    useage.pasb64ASM.pasIf possible, please send these through to groupby at gmail.comthanks and regards,Jane 

  • brian -

    Those files are from the ICS package as mentioned in the info about the library.

  • Antonio Borges

    Dear Steve,
    I would like to receive your implementation in Delphi 6, it’s the only I can use in my activities.  Thanks in advance.
    Antonio Borges

  • http://www.mactonweb.com Web design London

    If you are interested I’ll let you know when my app. is released.Great work and thanks for sharing your skills.

    web Design london

  • Mohammad Droid

    i have error in utf8 tweets : how can i fix it ? ( i use last version
    tnx for help and great library :)

  • brian -

    Sorry I got no time for free support on this :(

  • Joan

    Dear brian, The rar that I downloaded had only the TwitterLib.pas file, seems it didn’t include the two other files you used:

    OverbyteIcsHttpProt.pas
    OverbyteIcsSha1.pas
    useage.pas b64ASM.pasIf possible, please send these through to joan@autochartering.com
    regards Joan

  • edenfm

    You need the ICS sockets library: http://www.overbyte.be

  • http://twitter.com/matteoriso Matteo Riso

    Hello Brian.
    I’m testing your code but I have some trouble with accented characters which are really common in Italian language. If i try to tweet  the message “Questa è una prova”, the TwitMee app gets an OAuth error. How can I solve this?

  • Isnowmaker

    Thanks for your source.
    Can I receive delphi example source file ?

  • Isnowmaker

    Dear brian..
    Can I receive 0.22 example source ?Thank you.

  • brian -
  • brian -
  • Hilal Demirel

    Hi Brian. Thanks a lot. But i have some problem about charset.
    How can i change charset?
    I need iso8959-9
    . Please help me

  • edenfm

    Sorry for the late reply; haven’t worked on this for ages, maybe I’ll review it sometime, been wanting to make a full OAuth1/2 lib for a while.

  • edenfm

    Hi, not sure what’s your issue.

  • Hilal Demirel

    i cant use ‘ü,ğ,ç,ı’ and i need. 

  • Hilal Demirel

    this code only utf-8 but i need this char (ü,i,ğ,ç,ö). can u help for this?

  • Stephen Timms

    [re:As of December 2012 Twitter api is using GZip in every callback]…so you’ll have to enable content encoding before every Get/Post call,I guess that means adding this line (please confirm)
    Options := [httpoEnableContentCoding];
     …and then load the result from a gzipped stream in the RequestDone procs.
    Please give an example of the Delphi code I need to put in the RequestDone procs.
    I’m using ICS V1.94 which I believe already handles gzip content encoding.

  • brian -

    that’s all you need, but stable ics release doesn’t work properly with gzip, install the latest daily v8: http://wiki.overbyte.be/arch/icsv8w.zip

  • brian -

    Also add OverbyteIcsHttpCCodZLib to project source.

  • Stephen Timms

    Thanks for your swift reply. I think I’ve got it working in Delphi6 now.

  • Dave

    Hi Stephen, Sorry to say I don’t really understand a word about what you are saying with enable content encoding. Could you possibly give some code as to what I should put and where. Many thanks

  • Dave C

    Is it possible to give some more detailed instructions for those of us that aren’t that clever. I am using D2007 and I can’t really get it to work at all and I am sure it is related to what you are saying above

  • Dave C

    That doesn’t work for me not least of which because it uses TFlatEditUnit which I can’t seem to locate a working download/install for D2007

  • brian -

    just replace it with a normal TEdit

  • brian -

    You have to modify my code, and before any Get/Post calls, simply add “Options := [httpoEnableContentCoding];”

  • Dave C

    The above code doesn’t work for me because I get ” Undeclared Identifier ExtraSendHeader “.   I have tried to look that up but all I can find is some relatively old posts on ICS where it seems to say that it is to do with a custom mod that you made to ICS , but would no longer be using because there was some slightly modified code that made it unnecessary.
    I would sincerely appreciate a solution.
    Many thanks

  • brian -

    Yeah.. that was a workaround I used at the time. Well I’ll do something, give me a couple days and I’ll release my new generic library with a new demo app for twitter; watch the front page for the post.

  • Dave C

    Hi Brian, thanks for the response, maybe I’m a bit stupid or something, but if I put that code on any line it simply gives me the error of 
    Undeclared Identifier Options, and Undeclared identifier httpoEnableContentcoding.
    Clearly I am not really understanding what you are suggesting, though I have no doubt that what you say works when correctly implemented

  • Dave C

    Hi Brian, that is Excellent, Thank you so much, I guess the new library will also get around the December 2012 issues that I have also been posting about.

  • brian -

    sorry, those are properties of THttpCli, so like.. with HttpCli1 do begin.. Options := etc

  • brian -

    I didn’t have time to convert my generic OAuth1 lib for this, but I uploaded a fixed version of the older Twitter lib, you can get it here: http://code.google.com/p/delphi-twitter-library/