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#7#format=2]

[download#7#format=1]

Twitter object unit:

001{
002You can contact me at: https://eden.fm
003 
004License Version: GPL v3
005 
006The contents of this file are subject to the GPL License Version
0073 (the "License"); you may not use this file except in compliance with
008the License. You may obtain a copy of the License at
009http://www.gnu.org/licenses/gpl.html
010 
011Software distributed under the License is distributed on an "AS IS" basis,
012WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013for the specific language governing rights and limitations under the
014License.
015 
016You may use the code freely for freeware and commercial applications, as long
017you keep a notice the software is using my library, and the original source
018of my code isn't modified.
019 
020TwitterLib for Delphi v0.1. Developed by https://eden.fm
021 
022Usage: see usage.pas for details.
023 
0243rd party: I'm using ICS' overbyte winsock library, which you can get
025at www.overbyte.be
026After you install that, you need to overwrite (or place in your app folder)
027the file "OverbyteIcsHttpProt.pas" which is included in the rar where you
028obtained this file. It's a slightly modified version of the ICS THttpCli
029component to ease a bit the header modifications before a call.
030 
031- b64asm: this is a very fast implementation I found to encode into base64
032I was originally using madshi's madCrypt unit, which was actually as fast,
033but this should be easier to distribute.
034 
035}
036 
037unit TwitterLib;
038 
039interface
040 
041Uses Windows, SysUtils, Classes, StdCtrls,
042 
043b64ASM, OverbyteIcsSha1, OverbyteIcsHttpProt;
044 
045Const
046RequestTokenURL = 'http://api.twitter.com/oauth/request_token';
047RequestAccessURL = 'http://api.twitter.com/oauth/access_token';
048RequestTwitURL = 'http://api.twitter.com/1/statuses/update.xml';
049 
050shell32 = 'shell32.dll';
051 
052{$EXTERNALSYM ShellExecute}
053function ShellExecute(hWnd: hWnd; Operation, FileName, Parameters,
054Directory: PWideChar; ShowCmd: Integer): HINST; stdcall;
055 
056Type
057TwitterRequests = (trDummy, trRequestToken, trRequestAccess, trTwit);
058 
059Type
060TwitterCli = class(TObject)
061private
062FOnReqDone: TNotifyEvent;
063FOnBeforeSocketCall: TNotifyEvent;
064// use this to set socket proxy option, since sockets are created/destroyed on demand
065procedure TriggerReqDone; virtual;
066procedure TriggerBeforeSocketCall; virtual;
067 
068procedure RecreateSocket;
069 
070// CallbackProc: pointer;
071// VCL handlers
072procedure HTTPClientDocEnd(Sender: TObject);
073procedure HTTPClientHeaderEnd(Sender: TObject);
074procedure HTTPClientRequestDone(Sender: TObject; RqType: THttpRequest;
075ErrCode: Word);
076procedure HTTPClientBeforeHeaderSend(Sender: TObject; const Method: string;
077Headers: TStrings);
078 
079procedure BuildSignature;
080procedure GetTimeStamp;
081procedure GetNonce;
082procedure GenerateBaseURL(Method, url: string);
083procedure ParseTokenandTokenSecret(rawResult: string);
084procedure ParseAccessData(rawResult: string);
085 
086public
087ConsumerKey: string;
088ConsumerSecret: string;
089 
090OAuthToken: string;
091OAuthTokenSecret: string;
092AccessToken: string;
093AccessTokenSecret: string;
094AccessUserID: string;
095AccessScreenName: string;
096 
097URLRequestToken: string;
098URLRequestAccess: string;
099URLTwit: string;
100SignBase: string;
101TStamp: string;
102Nonce: string;
103Signature: string;
104Postvars: Ansistring;
105AuthHeader: string;
106HTTPClient: THttpCli;
107RefURL: string;
108ResultStrings: TStringList;
109LastReq: TwitterRequests;
110DebugMode: Boolean;
111DebugMemo: TMemo;
112LastHttpStatus: Integer;
113AccessPIN: String;
114SendStatus: String;
115 
116Constructor Create(CKey, CSecret: string); // virtual;
117Destructor Destroy; override;
118 
119procedure RequestToken; // socket call
120procedure RequestAccess; // socket call
121procedure SendTwit(twit: string); // socket call
122procedure RequestPIN; // call browser
123 
124function RequestPinURL: string;
125procedure SetStoredLogin(AToken, ATokenSecret: string);
126published
127property OnReqDone: TNotifyEvent read FOnReqDone write FOnReqDone;
128property OnBeforeSocketCall: TNotifyEvent read FOnBeforeSocketCall
129write FOnBeforeSocketCall;
130end;
131 
132function UrlEncode2(const S: String): String;
133function UrlEncodeExceptUnicode(const S: String): String;
134function DateTimeToUnix(DelphiTime: TDateTime): Int64;
135function urlEncodeRFC3986(url: string): string;
136function HasUnicode(src: string): Boolean;
137function BuildHexedUtf8String(src: string): string;
138 
139implementation
140 
141function ShellExecute; external shell32 name 'ShellExecuteW';
142 
143function BuildHexedUtf8String(src: string): string;
144Var
145ut: utf8string;
146a: Integer;
147BinarySize: Integer;
148InputString: utf8string;
149StringAsBytes: array of Byte;
150begin
151Result := '';
152for a := 1 to length(src) do
153begin
154if Ord(src[a]) < 255 then
155begin
156if src[a] = ' ' then
157Result := Result + '%2520'
158else
159Result := Result + UrlEncode2(src[a]);
160end
161else
162begin
163ut := src[a];
164BinarySize := 3; // (Length(InputString) + 1) * SizeOf(Char);
165SetLength(StringAsBytes, BinarySize);
166Move(ut[1], StringAsBytes[0], BinarySize);
167Result := Result + '%25' + IntToHex(StringAsBytes[0], 2);
168Result := Result + '%25' + IntToHex(StringAsBytes[1], 2);
169Result := Result + '%25' + IntToHex(StringAsBytes[2], 2);
170end;
171end;
172end;
173 
174function HasUnicode(src: string): Boolean;
175Var
176a: Integer;
177begin
178Result := False;
179for a := 1 to length(src) do
180if Ord(src[a]) > 255 then
181Exit(True);
182end;
183 
184function DateTimeToUnix(DelphiTime: TDateTime): Int64;
185begin
186Result := Round((DelphiTime - 25569) * 86400);
187end;
188 
189function UrlEncode2(const S: String): String;
190var
191I: Integer;
192Ch: Char;
193begin
194Result := '';
195for I := 1 to length(S) do
196begin
197Ch := S[I];
198if ((Ch >= '0') and (Ch <= '9')) or ((Ch >= 'a') and (Ch <= 'z')) or
199((Ch >= 'A') and (Ch <= 'Z')) or (Ch = '.') or (Ch = '-') or (Ch = '_') or
200(Ch = '~') then
201Result := Result + Ch
202else
203begin
204// if HasUnicode(Ch) then Result := Result + BuildHexedUtf8String(Ch)
205{ else } Result := Result + '%' + IntToHex(Ord(Ch), 2);
206end;
207end;
208end;
209 
210function UrlEncodeExceptUnicode(const S: String): String;
211var
212I: Integer;
213Ch: Char;
214begin
215Result := '';
216for I := 1 to length(S) do
217begin
218Ch := S[I];
219if ((Ch >= '0') and (Ch <= '9')) or ((Ch >= 'a') and (Ch <= 'z')) or
220((Ch >= 'A') and (Ch <= 'Z')) or (Ch = '.') or (Ch = '-') or (Ch = '_') or
221(Ch = '~') or HasUnicode(Ch) then
222Result := Result + Ch
223else
224Result := Result + '%' + IntToHex(Ord(Ch), 2);
225end;
226end;
227 
228function urlEncodeRFC3986(url: string): string;
229var
230URL1: string;
231begin
232URL1 := UrlEncode2(url);
233URL1 := StringReplace(URL1, '+', ' ', [rfReplaceAll, rfIgnoreCase]);
234Result := URL1;
235end;
236 
237Constructor TwitterCli.Create(CKey, CSecret: string);
238begin
239inherited Create;
240 
241ConsumerKey := CKey;
242ConsumerSecret := CSecret;
243DebugMode := False;
244 
245URLRequestToken := RequestTokenURL;
246URLRequestAccess := RequestAccessURL;
247URLTwit := RequestTwitURL;
248 
249ResultStrings := TStringList.Create;
250end;
251 
252Destructor TwitterCli.Destroy;
253begin
254ResultStrings.Free;
255inherited Destroy;
256end;
257 
258procedure TwitterCli.BuildSignature;
259Var
260SignKey: string;
261begin
262SignKey := UrlEncode2(ConsumerSecret) + '&' + UrlEncode2(OAuthTokenSecret);
263Signature := { madCrypt.Encode } b64ASM.Base64Encode
264(HMAC_SHA1_EX(SignBase, SignKey));
265if DebugMode then
266if Assigned(DebugMemo) then
267with TMemo(DebugMemo) do
268begin
269Lines.Add('- Build Signature -');
270Lines.Add('SignKey=' + SignKey);
271Lines.Add('Signature=' + Signature);
272Lines.Add('----------------------------------');
273end;
274end;
275 
276procedure TwitterCli.GetTimeStamp;
277begin
278TStamp := IntToStr(DateTimeToUnix(Now));
279end;
280 
281procedure TwitterCli.GetNonce;
282Var
283a: Integer;
284begin
285Nonce := '';
286for a := 1 to 20 do
287Nonce := Nonce + Chr(Random(26) + 65);
288end;
289 
290procedure TwitterCli.GenerateBaseURL(Method, url: string);
291Var
292ver, tok, cbak: string;
293begin
294GetNonce;
295GetTimeStamp;
296if AccessPIN <> '' then
297ver := 'oauth_verifier=' + AccessPIN + '&'
298else
299ver := '';
300// if OAuthToken <> '' then tok := 'oauth_token=' + OAuthToken + '&' else tok := '';
301 
302tok := 'oauth_token=' + OAuthToken + '&';
303if LastReq <> trTwit then
304cbak := 'oauth_callback=oob&';
305 
306SignBase := Method + '&' + UrlEncode2(url) + '&' +
307UrlEncode2(cbak + 'oauth_consumer_key=' + ConsumerKey + '&' + 'oauth_nonce='
308+ Nonce + '&' + 'oauth_signature_method=HMAC-SHA1' + '&' +
309'oauth_timestamp=' + TStamp + '&' + tok + ver // access PIN if any
310+ 'oauth_version=1.0');
311 
312if SendStatus <> '' then
313SignBase := SignBase + UrlEncode2('&status=') + BuildHexedUtf8String
314(SendStatus);
315 
316if DebugMode then
317if Assigned(DebugMemo) then
318with TMemo(DebugMemo) do
319begin
320Lines.Add('- Generate Base URL -');
321Lines.Add('base=' + SignBase);
322Lines.Add('----------------------------------');
323end;
324end;
325 
326procedure TwitterCli.RequestToken;
327begin
328 
329LastReq := trRequestToken;
330 
331OAuthToken := '';
332OAuthTokenSecret := '';
333AccessToken := '';
334AccessTokenSecret := '';
335AccessPIN := '';
336 
337GenerateBaseURL('GET', URLRequestToken);
338BuildSignature;
339Postvars := 'oauth_consumer_key' + '=' + ConsumerKey + '&' +
340'oauth_signature_method' + '=' + 'HMAC-SHA1' + '&' + 'oauth_signature' + '='
341+ UrlEncode2(Signature) + '' + '&' + 'oauth_timestamp' + '=' + TStamp + '&'
342+ 'oauth_nonce' + '=' + Nonce + '&' + 'oauth_token' + '=' + OAuthToken + '&'
343+ 'oauth_callback' + '=' + 'oob' + '&' + 'oauth_version' + '=' + '1.0';
344 
345RecreateSocket;
346 
347HTTPClient.ExtraSendHeader := 'Authorization: OAuth oauth_nonce="' + Nonce +
348'", oauth_callback="oob", oauth_token="' + OAuthToken +
349'", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + TStamp +
350'", oauth_consumer_key="' + ConsumerKey + '", oauth_signature="' +
351UrlEncode2(Signature) + '", oauth_version="1.0"';
352 
353With HTTPClient do
354begin
355Reference := RefURL;
356RcvdStream := TMemoryStream.Create;
357// SendStream := TMemoryStream.Create;
358// SendStream.Write(postvars[1], Length(postvars));
359// SendStream.Seek(0, soFromBeginning);
360Accept := '*/*';
361url := URLRequestToken; // + '?' + postvars;
362ResultStrings.Clear;
363 
364if DebugMode then
365if Assigned(DebugMemo) then
366with TMemo(DebugMemo) do
367begin
368Lines.Add('- Request Token Start -');
369Lines.Add('postvars=' + Postvars);
370Lines.Add('url=' + url);
371Lines.Add('----------------------------------');
372end;
373 
374try
375GetAsync;
376except
377on E: Exception do
378begin
379RcvdStream.Destroy;
380RcvdStream := nil;
381// SendStream.Destroy; SendStream := nil;
382ResultStrings.Text := 'ERROR ' + E.Message;
383LastHttpStatus := HTTPClient.StatusCode;
384TriggerReqDone;
385FreeAndNil(HTTPClient);
386Exit;
387end;
388end; // try
389end; // with
390end;
391 
392procedure TwitterCli.RequestAccess;
393begin
394 
395LastReq := trRequestAccess;
396 
397GenerateBaseURL('GET', URLRequestAccess);
398BuildSignature;
399Postvars := 'oauth_consumer_key' + '=' + ConsumerKey + '&' + 'oauth_nonce' +
400'=' + Nonce + '&' + 'oauth_signature_method' + '=' + 'HMAC-SHA1' + '&' +
401'oauth_signature' + '=' + UrlEncode2(Signature) + '' + '&' +
402'oauth_timestamp' + '=' + TStamp + '&' + 'oauth_token' + '=' + OAuthToken +
403'&' + 'oauth_callback' + '=' + 'oob' + '&' + 'oauth_verifier' + '=' +
404AccessPIN + '&' + 'oauth_version' + '=' + '1.0'; // + '&' +
405// 'oauth_callback' + '=' + 'oob' + '&' +
406 
407RecreateSocket;
408 
409HTTPClient.ExtraSendHeader := 'Authorization: OAuth oauth_nonce="' + Nonce +
410'", oauth_callback="oob", oauth_token="' + OAuthToken +
411'", oauth_verifier="' + AccessPIN +
412'", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + TStamp +
413'", oauth_consumer_key="' + ConsumerKey + '", oauth_signature="' +
414UrlEncode2(Signature) + '", oauth_version="1.0"';
415 
416With HTTPClient do
417begin
418Reference := RefURL;
419RcvdStream := TMemoryStream.Create;
420url := URLRequestAccess; // + '?' + postvars;
421ResultStrings.Clear;
422 
423if DebugMode then
424if Assigned(DebugMemo) then
425with TMemo(DebugMemo) do
426begin
427Lines.Add('- Request Access Start -');
428Lines.Add('postvars=' + Postvars);
429Lines.Add('url=' + url);
430Lines.Add('----------------------------------');
431end;
432 
433try
434GetAsync;
435except
436on E: Exception do
437begin
438RcvdStream.Destroy;
439RcvdStream := nil;
440ResultStrings.Text := 'ERROR ' + E.Message;
441LastHttpStatus := HTTPClient.StatusCode;
442FreeAndNil(HTTPClient);
443TriggerReqDone;
444Exit;
445end;
446end; // try
447end; // with
448end;
449 
450procedure TwitterCli.SendTwit(twit: string);
451begin
452// showmessage(twit);
453// twit := URLEncode2(twit);
454 
455// fix issue, # + unicode fails
456 
457LastReq := trTwit;
458if HasUnicode(twit) then
459begin
460twit := UrlEncodeExceptUnicode(twit);
461// StringReplace(twit,'#','%2523',[rfReplaceAll]);
462SendStatus := twit;
463end
464else
465SendStatus := UrlEncode2(utf8Encode(twit));
466AccessPIN := '';
467 
468GenerateBaseURL('POST', URLTwit);
469BuildSignature;
470Postvars := 'oauth_consumer_key' + '=' + ConsumerKey + '&' + 'oauth_nonce' +
471'=' + Nonce + '&' + 'oauth_signature_method' + '=' + 'HMAC-SHA1' + '&' +
472'oauth_signature' + '=' + UrlEncode2(Signature) + '' + '&' +
473'oauth_timestamp' + '=' + TStamp + '&' + 'oauth_token' + '=' + AccessToken +
474'&' + 'oauth_callback' + '=' + 'oob' + '&' + 'oauth_version' + '=' + '1.0';
475 
476if HasUnicode(twit) then
477Postvars := 'status=' + { urlencode2 } ((utf8Encode(twit)))
478else
479Postvars := 'status=' + UrlEncode2(twit);
480 
481SendStatus := '';
482 
483RecreateSocket;
484 
485HTTPClient.ExtraSendHeader := 'Authorization: OAuth ' + 'oauth_consumer_key="'
486+ ConsumerKey + '", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' +
487TStamp + '", oauth_nonce="' + Nonce +
488'", oauth_version="1.0", oauth_token="' + AccessToken +
489'", oauth_signature="' + UrlEncode2(Signature) + '"';
490 
491With HTTPClient do
492begin
493Reference := RefURL;
494RcvdStream := TMemoryStream.Create;
495SendStream := TMemoryStream.Create;
496SendStream.Write(Postvars[1], length(Postvars));
497SendStream.Seek(0, soFromBeginning);
498url := URLTwit; // + '?' + postvars;
499ResultStrings.Clear;
500 
501if DebugMode then
502if Assigned(DebugMemo) then
503with TMemo(DebugMemo) do
504begin
505Lines.Add('- Request twit Start -');
506Lines.Add('postvars=' + Postvars);
507Lines.Add('url=' + url);
508Lines.Add('----------------------------------');
509end;
510 
511try
512PostAsync;
513except
514on E: Exception do
515begin
516RcvdStream.Destroy;
517RcvdStream := nil;
518SendStream.Destroy;
519SendStream := nil;
520ResultStrings.Text := 'ERROR ' + E.Message;
521LastHttpStatus := HTTPClient.StatusCode;
522FreeAndNil(HTTPClient);
523TriggerReqDone;
524Exit;
525end;
526end; // try
527end; // with
528end;
529 
530procedure TwitterCli.TriggerReqDone;
531begin
532if Assigned(FOnReqDone) then
533FOnReqDone(Self);
534end;
535 
536procedure TwitterCli.TriggerBeforeSocketCall;
537begin
538if Assigned(FOnBeforeSocketCall) then
539FOnBeforeSocketCall(Self);
540end;
541 
542procedure TwitterCli.HTTPClientDocEnd(Sender: TObject);
543begin
544//
545end;
546 
547procedure TwitterCli.HTTPClientBeforeHeaderSend(Sender: TObject;
548const Method: string; Headers: TStrings);
549begin
550if DebugMode then
551if Assigned(DebugMemo) then
552with TMemo(DebugMemo) do
553begin
554Lines.Add('- Socket Before Header Send -');
555Lines.Add(Headers.Text);
556Lines.Add('----------------------------------');
557end;
558end;
559 
560procedure TwitterCli.HTTPClientHeaderEnd(Sender: TObject);
561begin
562if DebugMode then
563if Assigned(DebugMemo) then
564with TMemo(DebugMemo) do
565begin
566Lines.Add('- Socket Header End -');
567Lines.Add(HTTPClient.RcvdHeader.Text);
568Lines.Add('----------------------------------');
569end;
570end;
571 
572procedure TwitterCli.HTTPClientRequestDone(Sender: TObject;
573RqType: THttpRequest; ErrCode: Word);
574Label CleanUp;
575begin
576if DebugMode then
577if Assigned(DebugMemo) then
578with TMemo(DebugMemo) do
579begin
580Lines.Add('- Request Done Socket DocEnd -');
581Lines.Add('result=' + ResultStrings.Text);
582Lines.Add('status code=' + IntToStr(HTTPClient.StatusCode));
583Lines.Add('headers=' + HTTPClient.RcvdHeader.Text);
584Lines.Add('----------------------------------');
585end;
586 
587if (RqType = httpGET) or (RqType = httpPOST) then
588begin
589if (ErrCode <> 0) or (HTTPClient.StatusCode <> 200) then
590Goto CleanUp;
591end
592else
593Exit;
594 
595try
596HTTPClient.RcvdStream.WriteBuffer(#0' ', 1);
597HTTPClient.RcvdStream.Position := 0;
598ResultStrings.LoadFromStream(HTTPClient.RcvdStream);
599finally
600end;
601 
602LastHttpStatus := HTTPClient.StatusCode;
603 
604if (LastReq = trRequestToken) and (LastHttpStatus = 200) then
605ParseTokenandTokenSecret(ResultStrings.Text);
606if (LastReq = trRequestAccess) and (LastHttpStatus = 200) then
607ParseAccessData(ResultStrings.Text);
608 
609CleanUp:
610 
611HTTPClient.RcvdStream.Destroy;
612HTTPClient.RcvdStream := nil;
613if LastReq = trTwit then
614begin
615HTTPClient.SendStream.Destroy;
616HTTPClient.SendStream := nil;
617end;
618FreeAndNil(HTTPClient);
619 
620TriggerReqDone;
621 
622end;
623 
624procedure TwitterCli.RecreateSocket;
625begin
626HTTPClient := THttpCli.Create(nil);
627With HTTPClient do
628begin
629OnDocEnd := HTTPClientDocEnd;
630OnHeaderEnd := HTTPClientHeaderEnd;
631OnRequestDone := HTTPClientRequestDone;
632OnBeforeHeaderSend := HTTPClientBeforeHeaderSend;
633TriggerBeforeSocketCall;
634end;
635end;
636 
637procedure TwitterCli.ParseTokenandTokenSecret(rawResult: string);
638begin
639// parse tokens after request token
640if Pos('oauth_callback_confirmed=true', rawResult) = 0 then
641begin
642LastHttpStatus := 0;
643Exit;
644end;
645 
646try
647Delete(rawResult, 1, Pos('=', rawResult));
648OAuthToken := Copy(rawResult, 1, Pos('&oauth_token_secret=',
649rawResult) - 1);
650Delete(rawResult, 1, Pos('=', rawResult));
651OAuthTokenSecret := Copy(rawResult, 1, Pos('&oauth_callback_confirmed=true',
652rawResult) - 1);
653except
654LastHttpStatus := 0;
655end;
656 
657if DebugMode then
658if Assigned(DebugMemo) then
659with TMemo(DebugMemo) do
660begin
661Lines.Add('- Parse Token and TokenSecret -');
662Lines.Add('Token=' + OAuthToken);
663Lines.Add('TokenSecret=' + OAuthTokenSecret);
664Lines.Add('----------------------------------');
665end;
666 
667end;
668 
669procedure TwitterCli.RequestPIN;
670begin
671ShellExecute(0, nil, PChar('https://twitter.com/oauth/authorize?oauth_token='
672+ OAuthToken), '', '', SW_SHOWNORMAL);
673end;
674 
675function TwitterCli.RequestPinURL;
676begin
677Result := 'https://twitter.com/oauth/authorize?oauth_token=' + OAuthToken;
678end;
679 
680procedure TwitterCli.ParseAccessData(rawResult: string);
681begin
682// parse tokens after request acccess
683if Pos('user_id', rawResult) = 0 then
684begin
685LastHttpStatus := 0;
686Exit;
687end;
688 
689try
690Delete(rawResult, 1, Pos('=', rawResult));
691AccessToken := Copy(rawResult, 1, Pos('&oauth_token_secret=',
692rawResult) - 1);
693Delete(rawResult, 1, Pos('=', rawResult));
694AccessTokenSecret := Copy(rawResult, 1, Pos('&user_id=', rawResult) - 1);
695Delete(rawResult, 1, Pos('=', rawResult));
696AccessUserID := Copy(rawResult, 1, Pos('&screen_name=', rawResult) - 1);
697Delete(rawResult, 1, Pos('=', rawResult));
698AccessScreenName := rawResult;
699 
700OAuthToken := AccessToken;
701OAuthTokenSecret := AccessTokenSecret;
702except
703LastHttpStatus := 0;
704end;
705 
706if DebugMode then
707if Assigned(DebugMemo) then
708with TMemo(DebugMemo) do
709begin
710Lines.Add('- Parse Access Data -');
711Lines.Add('AccessToken=' + AccessToken);
712Lines.Add('AccessTokenSecret=' + AccessTokenSecret);
713Lines.Add('AccessUserID=' + AccessUserID);
714Lines.Add('AccessScreenName=' + AccessScreenName);
715Lines.Add('----------------------------------');
716end;
717 
718end;
719 
720procedure TwitterCli.SetStoredLogin(AToken: string; ATokenSecret: string);
721begin
722AccessToken := AToken;
723AccessTokenSecret := ATokenSecret;
724OAuthToken := AccessToken;
725OAuthTokenSecret := AccessTokenSecret;
726end;
727 
728end.

usage

001// start by defining and creating the twitter object:
002 
003Var
004Twit: TwitterCli;
005 
006Twit := TwitterCli.Create(TKey, TSecret);
007with Twit do
008begin
009// You can specify a TMemo here for debugging purposes, which will output relevant
010// data sent and received to twitter.
011// DebugMode := True;
012// DebugMemo := Memo1;
013OnReqDone := TwitterCallBackProc;
014RefURL := 'https://eden.fm';
015end;
016 
017// TwitterCallBackProc is a simple method that's called after each request:
018procedure TTwitMeMain.TwitterCallBackProc(Sender: TObject);
019// TKey and TSecret are your app key and secret you get from Twitter after
020// you register your app with them
021 
022// you can also specify a callback for TriggerBeforeSocketCall
023// which will trigger just before a socket call. Here you can alter
024// the socket to specify a proxy by accessing Twit.HTTPClient
025// (as per ICS THttpCli properties)
026 
027// Next we need to request a token from Twitter:
028// If you had already done this step before you can skip it, look at the
029// end of this doc for details
030 
031Twit.RequestToken;
032 
033// Right after the call, control is given back to your application, since the
034// call is asynchronous (non-blocking). the callback proc will be called after
035 
036// after we get the initial token from twitter, we need to send the user to
037// twitter.com so they will login and get a PIN code to enter in your app
038 
039Twit.RequestPIN;
040// you could also use Twit.RequestPinURL
041// to get the URL in a string if you wish to copy it to the user in the
042// clipboard or any other means, in case your app fails to launch the URL
043// in the browser
044 
045// once done, the user has to give the PIN to us, in an edit box for example,
046// then we tell the library the pin and request the final access tokens:
047 
048Twit.AccessPIN := Edit1.Text;
049Twit.RequestAccess;
050 
051// our callback proc will be called once again and we are ready to send
052// messages to twitter
053 
054// always check Twit.LastHttpStatus in the callback proc, if not 200 then
055// something went wrong. You can check the variables ResultStrings.Text
056// and LastHttpStatus for details on what went wrong
057 
058// now we can send a message with
059 
060Twit.SendTwit('test message');
061 
062// you can also use unicode here, like Japanese kanjis
063// tested also with problematic symbols like # $ ! ' & etc
064 
065// * Note about access request: after you complete the acess steps,
066// you can store these 2 string variables:
067//
068// Twit.AccessToken
069// Twit.AccessTokenSecret
070 
071// and simply do: SetStoredLogin(a,b);
072// after creating the twitter object (a and b being those 2 vars we stored
073// and your app is ready to send without any previous steps
074 
075// And that's it, pretty simple. Note that this is a very simple implementation
076// and we should check for other status codes from Twitter. I will be updating
077// the library to fully implement the entire API eventually.
078 
079// a little more help. this is what my callback proc on TwitMee looks like:
080 
081procedure TTwitMeMain.TwitterCallBackProc(Sender: TObject);
082begin
083if Twit.LastHttpStatus <> 200 then
084begin
085Label1.Font.Color := clRed;
086Label1.Caption := 'Error communicating with Twitter.';
087Exit;
088end;
089 
090if Twit.LastReq = trRequestToken then
091begin
092FlatEdit1.Text := 'Enter PIN here and click on Send button';
093Twit.RequestPIN;
094Exit;
095end;
096if Twit.LastReq = trRequestAccess then
097begin
098Label1.Font.Color := clWhite;
099Label1.Caption := 'Ready to send.';
100Authenticated := True;
101FlatEdit1.Text := '';
102SaveSettings;
103Exit;
104end;
105if Twit.LastReq = trTwit then
106begin
107FlatEdit1.Text := '';
108Label1.Caption := 'Message sent.';
109Exit;
110end;
111end;
Categories: Delphi stuff, Software Tags:
  1. brian –
    January 11th, 2013 at 00:45 | #1

    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/

  2. brian –
    January 10th, 2013 at 01:29 | #2

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

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

    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.

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

    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

  5. brian –
    January 10th, 2013 at 01:16 | #5

    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.

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

    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

  7. brian –
    January 10th, 2013 at 00:58 | #7

    just replace it with a normal TEdit

  8. brian –
    January 10th, 2013 at 00:58 | #8

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

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

    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

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

    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

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

    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

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

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

  13. brian –
    December 16th, 2012 at 17:59 | #13

    Also add OverbyteIcsHttpCCodZLib to project source.

  14. brian –
    December 16th, 2012 at 17:52 | #14

    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

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

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

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

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

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

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

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

    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.

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

    Hi, not sure what’s your issue.

  20. Hilal Demirel
    June 8th, 2012 at 14:17 | #20

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

  21. brian –
    April 13th, 2012 at 02:47 | #21
  22. brian –
    April 13th, 2012 at 02:47 | #22
  23. Isnowmaker
    April 13th, 2012 at 02:18 | #23

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

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

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

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

    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?

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

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

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

    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

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

    Sorry I got no time for free support on this 🙁

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

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

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

    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

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

    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

  32. brian –
    October 23rd, 2011 at 22:36 | #32

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

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

    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 

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

    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

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

    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

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

    Thanks you very much for the fast reply!

  37. brian –
    September 24th, 2011 at 13:58 | #37

    sent

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

    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

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

    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.

  40. brian –
    September 22nd, 2011 at 14:39 | #40

    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 🙂

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

    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 

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

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

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

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

  44. brian –
    July 26th, 2011 at 18:05 | #44

    sent 🙂

  45. July 26th, 2011 at 14:59 | #45

    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.

  1. No trackbacks yet.
You must be logged in to post a comment.