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).

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:
  1. July 26th, 2011 at 14:59 | #1

    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.

  2. brian -
    July 26th, 2011 at 18:05 | #2

    sent :)

  3. Purrpurrpurr11
    July 29th, 2011 at 11:42 | #3

    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. =)

  4. August 5th, 2011 at 15:09 | #4

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

  5. Steve
    September 21st, 2011 at 00:18 | #5

    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 

  6. brian -
    September 22nd, 2011 at 14:39 | #6

    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 :)

  7. Steve
    September 23rd, 2011 at 03:08 | #7

    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.

  8. Victor
    September 24th, 2011 at 12:47 | #8

    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

  9. brian -
    September 24th, 2011 at 13:58 | #9

    sent

  10. Victor
    September 24th, 2011 at 15:02 | #10

    Thanks you very much for the fast reply!

  11. October 10th, 2011 at 09:13 | #11

    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

  12. October 10th, 2011 at 09:30 | #12

    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

  13. Jane
    October 23rd, 2011 at 16:33 | #13

    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 

  14. brian -
    October 23rd, 2011 at 22:36 | #14

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

  15. Antonio Borges
    November 2nd, 2011 at 15:20 | #15

    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

  16. December 3rd, 2011 at 21:26 | #16

    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

  17. Mohammad Droid
    December 17th, 2011 at 07:52 | #17

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

  18. brian -
    December 18th, 2011 at 01:53 | #18

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

  19. Joan
    February 27th, 2012 at 15:37 | #19

    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

  20. edenfm
    February 27th, 2012 at 15:54 | #20

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

  21. April 3rd, 2012 at 10:02 | #21

    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?

  22. Isnowmaker
    April 13th, 2012 at 00:21 | #22

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

  23. Isnowmaker
    April 13th, 2012 at 02:18 | #23

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

  24. brian -
    April 13th, 2012 at 02:47 | #24
  25. brian -
    April 13th, 2012 at 02:47 | #25
  26. Hilal Demirel
    June 8th, 2012 at 14:17 | #26

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

  27. edenfm
    June 8th, 2012 at 14:35 | #27

    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.

  28. edenfm
    June 8th, 2012 at 14:35 | #28

    Hi, not sure what’s your issue.

  29. Hilal Demirel
    June 8th, 2012 at 15:59 | #29

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

  30. Hilal Demirel
    June 8th, 2012 at 16:00 | #30

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

  31. Stephen Timms
    December 16th, 2012 at 17:32 | #31

    [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.

  32. brian -
    December 16th, 2012 at 17:52 | #32

    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

  33. brian -
    December 16th, 2012 at 17:59 | #33

    Also add OverbyteIcsHttpCCodZLib to project source.

  34. Stephen Timms
    December 19th, 2012 at 00:24 | #34

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

  35. Dave
    January 10th, 2013 at 00:45 | #35

    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

  36. Dave C
    January 10th, 2013 at 00:50 | #36

    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

  37. Dave C
    January 10th, 2013 at 00:54 | #37

    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

  38. brian -
    January 10th, 2013 at 00:58 | #38

    just replace it with a normal TEdit

  39. brian -
    January 10th, 2013 at 00:58 | #39

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

  40. Dave C
    January 10th, 2013 at 01:00 | #40

    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

  41. brian -
    January 10th, 2013 at 01:16 | #41

    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.

  42. Dave C
    January 10th, 2013 at 01:16 | #42

    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

  43. Dave C
    January 10th, 2013 at 01:21 | #43

    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.

  44. brian -
    January 10th, 2013 at 01:29 | #44

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

  45. brian -
    January 11th, 2013 at 00:45 | #45

    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/

  1. No trackbacks yet.