Solved

Delphi blogger.com login

Posted on 2007-04-07
58
2,750 Views
Last Modified: 2013-11-23
I have a problem with log in to blogger.com. I'm using Delphi 7 with Indy 9. The problem is that I'm not getting logged in correctly.  Here is the code. Please help me with this. Thank you.


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdIOHandler, IdIOHandlerSocket, IdSSLOpenSSL, IdBaseComponent,
  IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, StdCtrls;

type
  TForm1 = class(TForm)
    IdHTTP1: TIdHTTP;
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Memo1: TMemo;
    IdSSLIOHandlerSocket1: TIdSSLIOHandlerSocket;
    Memo2: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var FormLogin, LoginRedirect : TStringList;
  FindString, RedirectUrl : string;
  i : integer;
begin

FormLogin := TStringList.Create;
LoginRedirect := TStringList.Create;

IdHTTP1 := TIdHTTP.Create(nil);
IdHTTP1.HandleRedirects := true;
IdHTTP1.AllowCookies := true;

IdSSLIOHandlerSocket1 := TIdSSLIOHandlerSocket.Create(Application);
IdHTTP1.IOHandler := IdSSLIOHandlerSocket1;

FormLogin.Values['continue'] := 'https%3A%2F%2Fwww.google.com%2Faccounts%2FManageAccount%3Fskipvpage%3Dtrue%26service%3Dblogger%26continue%3Dhttp%3A%2F%2Fwww2.blogger.com%2Floginz%3Fd%3Dhttp%3A%2F%2Fwww2.blogger.com';
FormLogin.Values['service'] := 'blogger';
FormLogin.Values['skipvpage'] := 'true';
FormLogin.Values['Email'] := 'testmeblogger@yahoo.com';
FormLogin.Values['Passwd'] := 'testmeblogger123';
FormLogin.Values['PersistentCookie'] := 'yes';
FormLogin.Values['rmShown'] := '1';
FormLogin.Values['signIn'] := 'Sign+in';

//IdHTTP1.ProxyParams.ProxyPort := 8089;
//IdHTTP1.ProxyParams.ProxyServer := 'localhost';

Memo1.Text := IdHTTP1.Post('https://www.google.com/accounts/LoginAuth?continue=http%3A%2F%2Fwww2.blogger.com%2Floginz%3Fd&service=blogger', FormLogin);


// this is a code that i write to extract url we need to redirect to continue with login process
LoginRedirect.Text := Memo1.Text;
FindString := '<meta content="0;';

  i := 0;
  If Pos(FindString, LoginRedirect.Text)<> 0 then
  begin
     while not (LoginRedirect.Text[Pos(FindString, LoginRedirect.Text) + 23 + i + 1] = '"') do
     begin
       RedirectUrl := RedirectUrl + LoginRedirect.Text[Pos(FindString, LoginRedirect.Text) + 23 + i];
       i := i + 1;
     end;
  end;

  //ShowMessage(RedirectUrl);

// go to extracted url
Memo2.Text := IdHTTP1.Get(RedirectUrl);

// as you can see in memo2 text we didn't get logged in, can someone fix this to work correctly, thank you!

end;

end.
0
Comment
Question by:DelphiHelpPlease
  • 29
  • 27
58 Comments
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
you've given us an emailaddress that we cannot work on. after logging in I get:

"Account Verification Needed".

so, if you verify the account in due time, I'll finish the project, otherwise, I'll just post it and you'll have to finish it yourself.

right now, my code gets to the page with the verification needed. if that is sufficient for you, let me know and I'll post the code.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
just to now, my code gets to the end but i don't now why is not login correctly, just look into my code and run it, you will see what i'm talking about
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
I created a google account so I can have some correct tests, being able to corss-check with a browser to see that I get where I want.
now, you might be experiencing the same problem as I did, in which case, we're a little out of luck. we'll need to implement the xmlhttprequest thingie in order to get stuff working.

the reason I'm not going via your approach is because I don't like it :) I prefer going via the browser way :)

this is my code:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdHTTP, IdCookieManager, StdCtrls, IdServerIOHandler, IdSSLOpenSSL,
  IdIOHandler, IdIOHandlerSocket;

type
  TForm1 = class(TForm)
    IdHTTP1: TIdHTTP;
    IdCookieManager1: TIdCookieManager;
    Memo1: TMemo;
    IdSSLIOHandlerSocket1: TIdSSLIOHandlerSocket;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses strutils, ComObj;

procedure TForm1.FormCreate(Sender: TObject);
  procedure setcookies;
  var j, count:integer;
  begin
    count:=IdCookieManager1.CookieCollection.count;
    for j:=1 to count do
      IdHTTP1.Request.RawHeaders.Add('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator+IdCookieManager1.CookieCollection.Items[j-1].CookieText);
  end;

  function getPage(url:string; postData:TStrings=nil; handleredirects:boolean=true):string;
  begin
//    application.processmessages;
    IdHTTP1.HandleRedirects:=handleredirects;
    setCookies;
    try
      if postData=nil then result:=idhttp1.Get(url)
                      else result:=idhttp1.Post(url, postData);
    except on e: EIdHTTPProtocolException do
    begin
      if e.ReplyErrorCode<>302 then
         raise e;
        // now this is the redirect
        setcookies;
        result:=idhttp1.Get(IdHTTP1.Response.Location);// follow redirect
      end;
    end;
  end;
var Params: TStringList;
    HTML, loginurl: String;
    ga3t, url:string;
    i:integer;
begin
  Params := TStringList.Create;
  try
    getPage('https://www2.blogger.com/login.g');
    html:=getPage('https://www.google.com/accounts/ServiceLoginBox?service=blogger&amp;continue=http%3A%2F%2Fwww2.blogger.com%2Floginz%3Fd%3D'+
        'http%253A%252F%252Fwww2.blogger.com&amp;alwf=true&amp;uilel=3&amp;skipvpage=true&amp;rm=false&amp;naui=8&amp;showra=1&amp;fpui=2&amp;hl=en&amp;nui=1&amp;alinsu=1');
// the above break is to overcome the string literal max length of 255

    i:=posex('value',html,pos('GA3T', html))+7;// 7=length(value=")
    ga3t:=copy(html,i,posex('"',html,i)-i);
    Params.values['service']:='blogger';
    Params.values['GA3T']:=ga3t;
    Params.values['Email']:=[email account here]
    Params.values['Passwd']:=[password here]
    Params.values['PersistentCookie']:='yes';
    Params.values['rmShown']:='1';
    Params.values['null']:='Sign in';

    HTML := getPage('https://www.google.com/accounts/ServiceLoginBoxAuth', params);
    // now do the js redirect
    i:=posex('href=',html,pos('id="clickToContinue"', html))+6;
    url:=copy(html,i,posex('"',html,i)-i);

    html:=getpage(url);

    if pos('>Sign Out</a>', html)>0 then
    begin
//      need some xmlhttprequest thing going on here.
      use CreateOleObject('') to create the xmlhttprequest and use it to interact with google service
//      html:=getPage('http://www.blogger.com');
//      html:=getPage('http://www2.blogger.com/home');
    end                             else
      html:='';

    except on e: EIdHTTPProtocolException do
            begin
                memo1.lines.add(idHTTP1.response.ResponseText);
                memo1.lines.add(e.ErrorMessage);
            end;
       end;
    Params.Free;
    memo1.Lines.Text:=html;
    showmessage('Logged in? '+booltostr(pos('<a href="/logout.g">Sign out</a>', html)>0,true));
end;

end.

------------------------

I have to leave town in about 1 hour, so I can't make this work yet, BUT, this code keeps you logged into google (in some cases you do need to set cookies manually. not sure why, it's something I noticed like 2 years ago and ever since that time I am setting the cookies manually: better safe than sorry :) )

if it's not such an urgent issue for you, I'll get back on this after I return, on Thursday.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
I have also tried like this with GT3A, i have learned something new, my code for extracting gt3a was much longer :) but i had some problems with this :) I will try your code and post results here.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
I have study and run your code peace by peace and your code is doing the same thing as mine, but with little different approach, first i have using gt3a but i have find a way how to by passit, my code also get you logged in to Google, but the problem is when the blogger.com part come. I don't have idea how to solve it, so i beg you to try. Thank you.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Man did you return? Can you finish it please.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
I just returned last night. Will get to it in an hour or two, just to finish catching up on emails and stuff ;)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok great.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
no news yet. I'm still on it (spending 15-30 minutes at a time, when a new idea comes to mind).
I might let indy rest for a while and give a shot with some IE automation. just to be on the safe side: would that be ok?
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
It needs to be with indy :(
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Can anyone else help me with this ?
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
you want the bad news or the bad news? :)

it's like this: I used lynx (unix text browser) to see if I can get through it. I couldn't, mainly because lynx didn't cope with some redirected url at one time. so I installed links (a newer unix text browser) with which I was able to login and all, BUT, it has the exact same behaviour as the indy project.

So, I again am convinced that there is some xmlhttprequest needed to be done somewhere OR there is something else (like an image, a js file, anything) just another resource that is setting a cookie or making a redirect.

the problem is, I didn't figure it out yet. I'll fire up ethereal and analyze a browsers behaviour, BUT, if the missing "thing" is done/used/get during a SSL session, I won't see it.

so, bottom line, prepare for a failure on this if you only want an indy solution.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
after a heavy investigation with ethereal, I found that the browser does "soemthing" after which it will issue a GET on for "loginz?parameters_gere" which also includes an "auth" parameter and some other, seems generated, parameters. the response to this GET command will set 2 cookies: "Blogger_SID" and "D2I" (this seems to be the blog name)
since most of the communication is done via SSL, I couldn't see what was going on. so, what I will try now, is to mimic the browser behaviour, except the dynamic part (JS & co), and hopefully I'll find something more relevant.

I'll keep you posted
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
I see that you have problem with ssl sniffing. It would be much easier for you if you use local proxy. I suggest you Paros Proxy (http://www.parosproxy.org/download.shtml). You will need java for it. Just install it and set http and https connections true this local proxy. I think it is much easier then using etheral for sniffing http traffic.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
will that show me the packets that go through SSL? have you tested that? because I'll need to see all http headers for the SSL communication.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Yes ofcourse, this is what I'm talking about :)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
If you have Firefox go to Tools-Options-Advenced-Nwetwork-Settings and write localhost and port into http proxy and put tick on "Use proxy server for all protocols"
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
ok. indeed it works. I also found the problem.

in my recent code, I GET https:\\www.google.com\accounts\CheckCookie?continue=blablabla
which in my case returns a page saying that my browser doesn't have cookies enabled. in firefoxes case, returns that loginz?blabla url that we need.

I'll check a little more to see why I'm getting the wrong page for that url.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok but indy handle redirect, goes true this page so it wouldn't be a problem.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
well, that certainly helped me to notice that I am missing some things from the login form :) following is teh complete list of items and their values

    Params.values['continue']:='http://www2.blogger.com/loginz?d=http%3A%2F%2Fwww2.blogger.com';
    Params.values['service']:='blogger';
    Params.values['nui']:='1';
    Params.values['naui']:='8';
    Params.values['fpui']:='2';
    Params.values['uilel']:='3';
    Params.values['skipvpage']:='true';
    Params.values['rm']:='false';
    Params.values['hl']:='en';
    Params.values['alfw']:='true';
    Params.values['alinsu']:='1';
    Params.values['GA3T']:=ga3t;
    Params.values['Email']:=[email account here]
    Params.values['Passwd']:=[password here]
    Params.values['PersistentCookie']:='no';
    Params.values['rmShown']:='1';
    Params.values['null']:='Sign in';

now. I've been trying to find why the url I am extracting now, with loginz?blabla is not setting the 2 needed cookies. so there is soemthing more I'm missing. I'll try to find that tomorrow night, because I'll be gone most of the day. hopefully, I'll see then what I'm missing now.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok thank you, but this data in form is not needed :)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
I think that   Params.values['PersistentCookie']:='no'; needs to be set to yes ?
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
not necessarely. it was set to yes at begining, but when I did the paros thing with firefox, by default it's on no. and so, I didn't want to do the login all over again, I just changed it in my code :)
basically, that tells if the cookies are presistent or valid only for the current session.
I'll try with "yes" tomorrow night, but I don't think it should make any difference.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
I just noticed that you are the asker behind this question: http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22496837.html

I'm afraid I changed my policy and I am now adding askers that disconsider me or my answers/questions to a blacklist. which basically means that if you feel that I must have a C/B grade in my records, then I feel that I will no longer help you. nothing personal, just got sick and tired of people especting proffesional input from the experts but treating them as dirt. the points and grades are the only thing we receive here. based on that, if we are good enough we will also receive some certificates. and that's that. we get no money no nothing. but we do make our best effort to provide best solutions to problems and expect the askers to fully cooperate in order for us to do that so we can both come to an understanding: you get the best possible solution that satisfies you, and we get an A.

You can of course wait for another expert to help you out. Thing is, after askers disconsider more experts, and the experts start adopting my point of view on the matter, a lot of askers will get ignored and the immediat effect will be that their questions will no longer be answered by competent experts or even worse: not answered at all. At least then, they will understand that we are not machines, but human beeings and we are not payed for what we do and the only reward is comming from the asker.

If we cannot get to an agreement regarding the troublesome question, I'm afraid the above will be put in practice.

BR
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Tell me how can i change it to A and i will do it. You ask something about asking admins, where can i do that ?
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
as I said, if you want to change something, grade, delete, paq (with refund) (which is also a viable solution), you must ask in commuity support.
there is a link in the uppoer right corner of the page named "support", which points to http://www.experts-exchange.com/support.jsp (maybe on your page it's not there? I'm using expert skin)
there you can select the best approriate zone for your problem (this is general). in this particular case you will probably want to post in http://www.experts-exchange.com/Community_Support/General/

I think the correct options in that particular question is either to delete the question or to PAQ with refund because you have solved the problem yourself (that's what EE suggests also in one of thei official documents). Of course, as I said in that question, if you really want to just change the grade from C to A, then I will not be against it. It's your choise, but I have told you the correct options for this particular situation.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:DelphiHelpPlease
Comment Utility
The grade has been changed. Can you solve my problem now.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
Sorry, I've been caught with the product I'm working on. I'll get to it in about 30 min.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok, thank you.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
any news ?
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
bad ones.
even though I've modified a lot of things in the setup of idhttp to mimic firefox, I am still missing some cookies. this was happening last night. Today I worked on my ongoing project for obvious reasons ;) If I'm luck to finish the needed bugfixes until tomorrow afternoon, I'll continue with this project. I'll take it one step at a time and make sure what indy sends and receives is the same as firefox send&receive. this will be a boring task but at least It'll pipoint the place where something is missing or returned incorrectly.

also, I started to consider the 2 complex possibilities:
- the google analytics cookies might need to be set (you never know what google is checking on their servers)
- and there are some places where an xmlhttprequest object is being used. so this also might be needed.
using the above mentioned step-by-step checking will make sure if one or both of the 2 complex situations are in place or not.

so I'll have more exact info tomorrow evening or the day after tomrrow.

sorry for the long time in solving this, but this is nothing I've ever seen in prespective to persistent http connections, and I've done quite some projects similar to this one.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok, thank you for your hard work.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
GOD. I cursed for a few minutes here. there is a stupid bug in paros which makes it add the cookies. you have option in edit to use or not session tracking. well, if its enabled, it will add teh cookies itself. if it is not enabled,... it will add the cokies itself. mother f***er.

I just couldn't understand why is indy so stupid as to add 2 sets of cookies. I ended up disableing all cookies in indy, first, by clearing them before each release, then by setting a ccokie3 value instead of cookie (which of course didn't get set, but cookies still were sent) and finally, by using the onnewcookie event of the cookie manager and explicitly rejecting the cookies. and when I saw that the cookies were still sent, I was pulling my hair for almost 2 hours, looked 2 or 3  times through the whole indy sources which related to the http send/get and cookie handling and just couldn't find the problem. and then I thought to investigate paros. aaaaaaaaa. few days fo wasted time. I actually spent almost 7 hours just today on this. jesus.

well, I'll take a small break to chill out and then get to it. hopefully this paros is not getting in the middle of other stuff as well.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
after redoing things, I got to the
https:\\www.google.com\accounts\CheckCookie?blablabla
where I get some weird things with the cookies again. and since it past 23 hours, I'll hit the bed and get to it fresh in the morning. at least now I'll investigate starting from paros and not indy :)
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
ok. almost good news. I made it work through paros. but it doesn't work without paros. still investigating.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
hm... after I tried a few http sniffers, I wanted to post the actual code and noticed that it wasn't working anymore (the session tracking was not turned off) so I turned it on (I used to keep it turned on and always clear the session before each test; I know, boring) and it worked. so I guess my mechanism is missing a cookie somehow. I'll investigate some more tomorrow. if you want, I can post the code I have now, but you need to keep in mind that session tracking must be checked and before every test, cleared out (not tested without clearing it out...)

I'll turn off in about 30 min so if you're around and want the code as it is now, just let me know. in any case, hopefully tomorrow I'll have the correct version :D
(I've been reading the rfc's again, and made quite some notes. actually, at least 50% of the lines from the unit are comments :) )
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok thank you very much
0
 
LVL 28

Accepted Solution

by:
ciuly earned 500 total points
Comment Utility
well, finally :D

the code is a mess. BUT ... it's full of comments :)

first: why I choosed to control the cookies myself?
well, first of all, I noticed that indy has some problems handling cookies itself, and this is true when there is a redirect involved. Now, I didn't test at that time if the just mentioned statement is 100% correct or not (that would have involved a lot of time for testing) but at that time, setting the cookies maunally, did work. With this project, I have gone a little higher with the cookie managing and handling, and some, if not most, of the cookie related stuff is more or less rfc-compliant.

so, as you will see, there are a lot of line codes that are commented out. they were used in tests I made to see which approach is better. You can improve a little the code, clean it up :) I won't do that now because it's 00:21 which is pretty late.

let me know if you have any issues with this.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdHTTP, IdCookieManager, StdCtrls, IdServerIOHandler, IdSSLOpenSSL,
  IdIOHandler, IdIOHandlerSocket, idAuthentication, IdHeaderList,
  IdException, IdCookie, IdURI, IdGlobal;

type
  TForm1 = class(TForm)
    IdHTTP1: TIdHTTP;
    CookieManager: TIdCookieManager;
    Memo1: TMemo;
    IdSSLIOHandlerSocket1: TIdSSLIOHandlerSocket;
    BackupCookieManager: TIdCookieManager;
    email: TEdit;
    passwd: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    UseProxy: TCheckBox;
    Button1: TButton;
    procedure CookieManagerNewCookie(ASender: TObject;
      ACookie: TIdCookieRFC2109; var VAccept: Boolean);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses strutils, ComObj;

  function isExpiredCookie(c:TIdCookieRFC2109):boolean;
  var s:string;
  begin
    s:=c.Expires;
    result:=((Length(S) > 0) and (GMTToLocalDateTime(S) < Now)) or (c.Value='EXPIRED');
  end;

  function isCookieForPath(c:TIdCookieRFC2109; path:string):boolean;
  begin
    result:=true;{$Message warn 'implement this'}
  end;

procedure TForm1.CookieManagerNewCookie(ASender: TObject;
  ACookie: TIdCookieRFC2109; var VAccept: Boolean);
var i:integer;
begin
  i:=0;
  while (i<BackupCookieManager.CookieCollection.Count) and ((not sametext(BackupCookieManager.CookieCollection[i].CookieName, ACookie.CookieName))
    or (not sametext(BackupCookieManager.CookieCollection[i].Domain, ACookie.Domain)) or (not sametext(BackupCookieManager.CookieCollection[i].Path, ACookie.Path)))
    do
    inc(i);
  if i<BackupCookieManager.CookieCollection.Count then
  begin
    if isExpiredCookie(ACookie) then
    begin
//      if ACookie.CookieName<>'GA3T' then
        BackupCookieManager.CookieCollection[i].Free
    end                         else
      BackupCookieManager.CookieCollection[i].Assign(ACookie);
  end                                             else
    BackupCookieManager.CookieCollection.Add.Assign(ACookie);
  VAccept:=false;
end;

procedure TForm1.Button1Click(Sender: TObject);

  procedure saveit(html:string);// put a breakpoint in the end of this procedure to see all intermediary html responses
  begin
    with tfilestream.create('page.html',fmcreate) do
    try
      write(pansichar(html)^,length(html));
    finally
      free;
    end;
  end;

  procedure cleanupExpired;
  var i:integer;
  begin
    i:=0;
    while i<BackupCookieManager.CookieCollection.Count do
    begin
      if isExpiredCookie(BackupCookieManager.CookieCollection[i]) then BackupCookieManager.CookieCollection[i].Free
                                                                  else inc(i);
    end;
  end;

  procedure clearCookies;
  var j:integer;
  begin
    j:=0;
    while j<IdHTTP1.Request.RawHeaders.Count do
    begin
      if pos('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator, IdHTTP1.Request.RawHeaders[j])=1 then
        IdHTTP1.Request.RawHeaders.delete(j)                                                          else
        inc(j);
    end;
    j:=0;
    while j<IdHTTP1.Request.CustomHeaders.Count do
    begin
      if pos('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator{this is used when setting so it's ok}, IdHTTP1.Request.CustomHeaders[j])=1 then
        IdHTTP1.Request.CustomHeaders.delete(j)                                                                                                else
        inc(j);
    end;
    cleanupExpired;
  end;

{  procedure moveCookies;
//  var i:integer;
  begin
    while CookieManager.CookieCollection.Count>0 do
    begin
      BackupCookieManager.CookieCollection.Add.Assign(CookieManager.CookieCollection[0]);
      CookieManager.CookieCollection[0].Free;
    end;
//    CookieManager.CookieCollection.clear;
  end;  {}

  procedure setcookies(forUrl:string);
  var j, count:integer;
      all, cv:string;
      c:TIdCookieRFC2109;
      u:TIdUri;
  begin
//    moveCookies;
    clearCookies;

    count:=BackupCookieManager.CookieCollection.count;
    all:='';
    u:=TIdUri.Create(forUrl);
    for j:=1 to count do{$Message warn 'todo: order (if needed) according to path'}
    //If multiple cookies satisfy the criteria above, they are ordered in
    //the Cookie header such that those with more specific Path attributes
    //precede those with less specific. (section 4.3.4 from rfc2109)
    begin
      c:=BackupCookieManager.CookieCollection.Items[j-1];
      if c.IsValidCookie(u.Host) and isCookieForPath(c, u.Path) and not isExpiredCookie(c) then
      begin
        cv:=c.CookieName+'='+c.Value;
        IdHTTP1.Request.RawHeaders.Add('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator+' '+cv);
//        IdHTTP1.Request.CustomHeaders.Add('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator+' '+cv);// paros does this for some reason. not sure if it's needed
        all:=all+cv+'; ';// this might be needed to be done differently for different paths.
        // so if you have for example a set of cookies for / and anotehr one for /somepath, it might be needed to Cookie: list header entries.
        // didn't read the RFC for this so I am only guessing. for now, this works fine.
      end;
    end;
    if all<>'' then
    begin
      delete(all,length(all)-1,2);
//      IdHTTP1.Request.RawHeaders.Add('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator+' '+all);
      idhttp1.Request.CustomHeaders.Add('Cookie'+IdHTTP1.Request.RawHeaders.NameValueSeparator+' '+all);
    end;
    u.free;
  end;

  function getPage(url:string; postData:TStrings=nil; handleredirects:boolean=false):string;
  var u:string;
      i:integer;
  begin
//    application.processmessages;
    IdHTTP1.HandleRedirects:=handleredirects;
    setCookies(url);
    try
      if postData=nil then result:=idhttp1.Get(url)
                      else result:=idhttp1.Post(url, postData);
    except
      on e: EIdHTTPProtocolException do
      begin
        if (e.ReplyErrorCode div 100)<>3 then
           raise e;
          // now this is the redirect
          u:=IdHTTP1.Response.Location;
          if pos('://',u)=0 then// we need a valid location
          begin
           i:=posex('/',url,pos('.',url));
            if i>0 then
             delete(url,i,length(url));
            if url[length(url)]='/' then
              delete(url,length(url),1);
            if u[1]<>'/' then
             u:='/'+u;
            u:=url+u;
         end;

         result:=getpage(u, postData, handleRedirects);// follow redirect
      end;
      on e: EIdConnClosedGracefully do// workaround for what seems to be a connection closing from paros
        result:=getpage(url, postData, handleRedirects);
      on e: Exception do
        raise e;
    end;
    saveIt(result);
  end;
 
var Params: TStringList;
    HTML: String;
    ga3t, url:string;
    i:integer;
begin
  assert(email.text<>'');
  assert(passwd.text<>'');
  // mimic firefox
  idhttp1.Request.UserAgent:='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11';
  idhttp1.Request.Accept:='text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
  idhttp1.Request.AcceptLanguage:='en-us,en;q=0.5';
//  idhttp1.Request.Connection:='keep-alive';
//  idhttp1.Request.AcceptEncoding:='gzip,deflate';
  idhttp1.Request.AcceptCharSet:='ISO-8859-1,utf-8;q=0.7,*;q=0.7';
  idhttp1.Request.CustomHeaders.Add('Keep-Alive: 300');
  idhttp1.Request.CustomHeaders.Add('Connection: keep-alive');
  idhttp1.Request.ContentType:='';

  if useproxy.checked then
  begin
    idhttp1.ProxyParams.ProxyPort:=8080;
    idhttp1.ProxyParams.ProxyServer:='localhost';
  end;

  Params := TStringList.Create;

  try
    url:='https://www2.blogger.com/login.g';
    html:=getPage(url);
    // sets 1 cookie:
    // - S=blogger=GZToBYmGIRnzcAWwVvqszQ; Domain=.blogger.com; Path=/

    idhttp1.Request.Referer:=url;
    // send cookies: S=blogger=GZToBYmGIRnzcAWwVvqszQ
    i:=pos('iframe src=', html)+12;//12=length(iframe src=")
    url:=copy(html,i,posex('"',html,i)-i);
    url:=stringreplace(url,'&amp;', '&', [rfReplaceAll, rfIgnoreCase]);
    html:=getPage(url);
    // sets 2 cookies:
    // - GoogleAccountsLocale_session=en
    // - GA3T=r1jGWSDh6FA

    i:=posex('value',html,pos('GA3T', html))+7;// 7=length(value=")
    ga3t:=copy(html,i,posex('"',html,i)-i);
    Params.values['continue']:='http://www2.blogger.com/loginz?d=http%3A%2F%2Fwww2.blogger.com';
    Params.values['service']:='blogger';
    Params.values['nui']:='1';
    Params.values['naui']:='8';
    Params.values['fpui']:='2';
    Params.values['uilel']:='3';
    Params.values['skipvpage']:='true';
    Params.values['rm']:='false';
    Params.values['hl']:='en';
    Params.values['alfw']:='true';
    Params.values['alinsu']:='1';
    Params.values['GA3T']:=ga3t;
    Params.values['Email']:=email.text;//[email account here]
    Params.values['Passwd']:=passwd.text;//[password here]
//    Params.values['PersistentCookie']:='no';
    Params.values['rmShown']:='1';
    Params.values['null']:='Sign in';

    idhttp1.Request.Referer:=url;
    idhttp1.Request.ContentType:='application/x-www-form-urlencoded';
    // send cookies: GoogleAccountsLocale_session=en; GA3T=r1jGWSDh6FA
    HTML := getPage('https://www.google.com/accounts/ServiceLoginBoxAuth', params);
    // sets 8 cookies:
    // - GoogleAccountsLocale_session=en
    // - SID=DQAAAGoAAAAFMpqWBvaol9t61QDdcQkORiDRyy6laLqmxuWQ97Dcogq5o05Ndhmymk82SFnFVg6M0fveOe5ox4HQJsreaHZYAi1s3llAK27qh2usYkswJnSZVrd_Tx3XTk7OtxQQjItf71MHX5QIZ7SV6wdJe7Fc;Domain=.google.com;Path=/
    // - LSID=EXPIRED;Domain=.google.com;Path=/;Expires=Mon, 01-Jan-1990 00:00:00 GMT
    // - LSID=EXPIRED;Path=/;Expires=Mon, 01-Jan-1990 00:00:00 GMT
    // - LSID=EXPIRED;Domain=www.google.com;Path=/accounts;Expires=Mon, 01-Jan-1990 00:00:00 GMT
    // - LSID=DQAAAG4AAADanAEjtwRXL-iUy0157EqeFN43KNkGbZk-hIQSc69PDet5u4D8_RWv-1xb6u_3tTXvFO677EbXLDgY-yE8O0pdPutCZr92kPckOWjcXaMuKKuXcvQalb0GeEmK4cE_JQpJZ9iM8LRXInhARGOtiMpW;Path=/accounts;Secure
    // - GA3T=; Expires=Fri, 13-Apr-07 14:07:12 GMT; Path=/
    // - GoogleAccountsLocale_session=en

    // notable differences above between indy and firefox:
    // 1. indy uses http protocol 1.0 for POST (this can be forced by configuration to 1.1 if needed)
    // 2. indy also url encodes the "." in the post parameters
    // 3. server replies with an extra header element: "Connection: Close" (might be because of using 1.0 protocol)

    // now do the js redirect
    i:=posex('href=',html,pos('id="clickToContinue"', html))+6;
    url:=copy(html,i,posex('"',html,i)-i);

//    getPage('https:\\www.google.com\accounts\CheckCookie?continue=http%3A%2F%2Fwww2.blogger.com%2Floginz%3Fd%3Dhttp%253A%252F%252Fwww2.blogger.com&service=blogger&hl=en&chtml=LoginDoneHtml&skipvpage=true&alinsu=1&naui=8');
    idhttp1.Request.Referer:='https://www.google.com/accounts/ServiceLoginBoxAuth';
    idhttp1.Request.ContentType:='';
    // send cookies:
    // GoogleAccountsLocale_session=en;
    // GA3T=r1jGWSDh6FA;
    // LSID=DQAAAG4AAADanAEjtwRXL-iUy0157EqeFN43KNkGbZk-hIQSc69PDet5u4D8_RWv-1xb6u_3tTXvFO677EbXLDgY-yE8O0pdPutCZr92kPckOWjcXaMuKKuXcvQalb0GeEmK4cE_JQpJZ9iM8LRXInhARGOtiMpW;
    // SID=DQAAAGoAAAAFMpqWBvaol9t61QDdcQkORiDRyy6laLqmxuWQ97Dcogq5o05Ndhmymk82SFnFVg6M0fveOe5ox4HQJsreaHZYAi1s3llAK27qh2usYkswJnSZVrd_Tx3XTk7OtxQQjItf71MHX5QIZ7SV6wdJe7Fc
    html:=getpage(url);
    // sets 5 cookies:
    // - GoogleAccountsLocale_session=en
    // - LSID=EXPIRED;Domain=.google.com;Path=/;Expires=Mon, 01-Jan-1990 00:00:00 GMT
    // - LSID=EXPIRED;Path=/;Expires=Mon, 01-Jan-1990 00:00:00 GMT
    // - LSID=EXPIRED;Domain=www.google.com;Path=/accounts;Expires=Mon, 01-Jan-1990 00:00:00 GMT
    // - LSID=blogger:DQAAAG4AAADanAEjtwRXL-iUy0157EqeFN43KNkGbZk-hIQSc69PDet5u4D8_RWv-1xb6u_3tTXvFO677EbXLDgY-yE8O0pdPutCZr92kPckOWjcXaMuKKuXcvQalb0GeEmK4cE_JQpJZ9iM8LRXInhARGOtiMpW;Path=/accounts;Secure

    // notable differences above between indy and firefox:
    // 1. firefox sends the cookie GA3T=r1jGWSDh6FA which my indy implementation doesn't. However, I'm not sure which one is correct.
    //    if you look at the previous get, the server returns GA3T=; Expires=Fri, 13-Apr-07 14:07:12 GMT; Path=/
    //    actually, it returns the expires field with one day before today, which basically means the cookie is epired.
    //    according to the 2109 RFC, if a cookie is received expired, then both the current cookie and existing cookie is discarded
    //    and thus not sent to the server (my understanding). more precisely, and I quote (section 4.3.3):
    //      If a user agent receives a Set-Cookie response header whose NAME is
    //      the same as a pre-existing cookie, and whose Domain and Path
    //      attribute values exactly (string) match those of a pre-existing
    //      cookie, the new cookie supersedes the old.  However, if the Set-
    //      Cookie has a value for Max-Age of zero, the (old and new) cookie is
    //      discarded.  Otherwise cookies accumulate until they expire (resources
    //      permitting), at which time they are discarded.
   
//    i:=pos('location.replace(',html)+18;//18=length(location.replace(")
    i:=pos('url=',html)+5;//18=length(url=')
    url:=copy(html,i,posex('''',html,i)-i);

    url:=stringreplace(url,'&amp;', '&', [rfReplaceAll, rfIgnoreCase]);
    idhttp1.Request.Referer:='';
{    idhttp1.Request.CustomHeaders.Delete(idhttp1.Request.CustomHeaders.IndexOfName('Connection'));
    idhttp1.Request.CustomHeaders.Add('Connection: keep-alive'); {}
    // above is attempt to overcome firefox difference explained below at differences
    // send cookies:
    // S=blogger=GZToBYmGIRnzcAWwVvqszQ;
    // __utma=238348806.1200250844.1176559960.1176559960.1176559960.1;
    // __utmb=238348806;
    // __utmc=238348806;
    // __utmz=238348806.1176559960.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none)
    html:=getpage(url);
    // sets 2 cookies:
    // - blogger_SID=DQAAAGwAAADDmZaiK1xHJTugfyJtyOZgkG-BcrPo5LUe3XW7IAMNVwqf2GxlprOjXlOzJG0fqa88mX8uotyGmfoh_Nl5lGkhJO-Ui4lnZHCecmL2X_tQ-VBnVQHjxa4Tr_Zr0OO23Obc5f_0_PbVnSbxh_N4RTwV; Domain=.blogger.com; Path=/
    // - B2I=Ciuly; Domain=.blogger.com
    // + redirects (302) to http://www2.blogger.com

    // notable differences above between indy and firefox:
    // 1. firefox, through paros, sends a header "Proxy-Connection: keep-alive", whereas indy remains at "Connection: keep-alive"
    //    I tried a small fix, commented above, but it doesn't seem to work. since this session returned the correct cookies and
    //    kept me logged in, I decided not to spend time on solving this as it might not even be a problem

    // send cookies:
    // S=blogger=GZToBYmGIRnzcAWwVvqszQ;
    // __utma=238348806.1200250844.1176559960.1176559960.1176559960.1;
    // __utmb=238348806;
    // __utmc=238348806;
    // __utmz=238348806.1176559960.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none);
    // blogger_SID=DQAAAGwAAADDmZaiK1xHJTugfyJtyOZgkG-BcrPo5LUe3XW7IAMNVwqf2GxlprOjXlOzJG0fqa88mX8uotyGmfoh_Nl5lGkhJO-Ui4lnZHCecmL2X_tQ-VBnVQHjxa4Tr_Zr0OO23Obc5f_0_PbVnSbxh_N4RTwV;
    // B2I=Ciuly
//    html:=getpage('http://www2.blogger.com');
// not needed, as it is deon by the redirect
    // doesn't set any cookie
    // + redirects (302) to http://www2.blogger.com/home

    // send cookies:
    // S=blogger=GZToBYmGIRnzcAWwVvqszQ;
    // __utma=238348806.1200250844.1176559960.1176559960.1176559960.1;
    // __utmb=238348806;
    // __utmc=238348806;
    // __utmz=238348806.1176559960.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none);
    // blogger_SID=DQAAAGwAAADDmZaiK1xHJTugfyJtyOZgkG-BcrPo5LUe3XW7IAMNVwqf2GxlprOjXlOzJG0fqa88mX8uotyGmfoh_Nl5lGkhJO-Ui4lnZHCecmL2X_tQ-VBnVQHjxa4Tr_Zr0OO23Obc5f_0_PbVnSbxh_N4RTwV;
    // B2I=Ciuly
//    html:=getpage('http://www2.blogger.com/home');
// not needed, as it is deon by the redirect

    // doesn't set any cookie

    except on e: EIdHTTPProtocolException do
            begin
                memo1.lines.add(idHTTP1.response.ResponseText);
                memo1.lines.add(e.ErrorMessage);
            end;
       end;
    Params.Free;
    memo1.Lines.Text:=html;
    showmessage('Logged in? '+booltostr(pos('<a href="/logout.g">Sign out</a>', html)>0,true));
end;

end.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
btw, I used charles for checking: http://www.xk72.com/charles/download.php

at least this one doesn't have session tracking :D (or at least I didn't find it, and of course, it is not interfearing)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Can you please upload project and pas file somewhere, i have some errors problems with delphi. Thank you
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
posted here: http://www.ciuly.com/delphi/indy/blogspotLogin/index.html

give it a quick try and let me know if you still have issues. if you do, don't forget to mention what they are ;)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
I'm getting error when i click go,

"Project Projext1.exe raised exception class EidSocketError with message Socket Error #10061 Connection refused"

it is somwhere here on  raise e; line

      on e: EIdConnClosedGracefully do// workaround for what seems to be a connection closing from paros
        result:=getpage(url, postData, handleRedirects);
      on e: Exception do
        raise e;
    end;
    saveIt(result);
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
"Socket Error #10061 Connection refused"
are you using a proxy to connect to the internet? if so, is it localhost:8080? if not, see at the begining of the code, there is an

  if useproxy.checked then
  begin
    idhttp1.ProxyParams.ProxyPort:=8080;
    idhttp1.ProxyParams.ProxyServer:='localhost';
  end;

change that to your proxy settings.

if you're not using a proxy to connect to teh internet, then don't check the use proxy checkbox. if you didn't, then all I can think of is that blogger.com refused the connection.. which is weird, because it works for me. I'll wait your reply before making any other assumptions :)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
i didn't use proxy and i didn't check useproxy I will try
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
i didn't use proxy and i didn't check useproxy I will try again
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
the code is indy 9 on delphi 7, so it should run fine out of the box. however, I've seen at least one case this year when the asker indeed encountered some issue, which turned out to be caused by something on his machine (I gave him the exe to test: the exe worked, the compiled code didn't). If you wish, I can also give you the exe, so to make sure if this is a compilation issue on your machine or not ;)
if not, maybe firewall? application protection something? who knows? you can also try running it on some other peoples machines to see if your compiled code runs on them, this will also tell if the machine/environment is to blame or not.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
ok give me exe, but i think it is some overflow in getpage function
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
here it is: http://www.ciuly.com/delphi/indy/blogspotLogin/executable.zip
what makes you think there is an overflow in getpage?

btw, my credentials are of form:
user@gmail.com
password for gmail account
dunno if that is your problem or not. maybe you are using the old login credentials? because I see on the site that there are 2 ways to login: old and new. I implemented for new.
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
It is working good with your exe, i'm using new login, i will try to do some test.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
in this case there are 2 possibilities:
- my environment has something that yours doesn't, which makes it work
- your environment has something that mine doesn't, which makes it not work
will be hard to track down which one is the case and where the problem lies. so this is what I suggest:
use step by step running (with F8), and pu breakpoints on the getpage calls. step over it (F8) and see where and what is not set correctly. most possibly cookies. since the code is commented, you should be able to see exactly what cookies need to be set (from comments) and what cookies are not set (in the watch window you will insert some watches:
- BackupCookieManager.CookieCollection.Count
- BackupCookieManager.CookieCollection[0]
- BackupCookieManager.CookieCollection[1]
- BackupCookieManager.CookieCollection[2]
- BackupCookieManager.CookieCollection[3]
- BackupCookieManager.CookieCollection[4]
- BackupCookieManager.CookieCollection[5]
etc, as much as you need. and identify the line which doesn't behave right. one idea would also be to install charles (link is given in one of my previous posts) and use it as a proxy to also see what indy is sending. this will indetify the place in code where the problems start. if we are lucky, I will have an idea why that happens :D if we're not, we'll just need to debug it some more (in terms of what gets compiled in, look at search paths and make sure there isn't some other code that is linked in and it shouldn't) (I had such a situation once when I had 2 units with the same name, one like 5 years old, and of course alreaady in the library path, and another one from last year, not in the library path as I was only using it on some projects, and then in one project in which I wanted to use it, I forgot to add it to the project search path, so the old one was used. it was a logging framework, and the functions didn't change so everything compiled, but the functionality was very different (thread support, dynamic stuff, control over log file output, etc, and I was debugging it for days and couldn't understand how in the world the log file is not apearing where it should (I even triple checked user rights and all that :)) )
so, idea is: everything is possible, so we need to make sure the environment is right and rule out all possible issues, one by one, until we find the one that is an issue.

hopefully it won't take long. btw, if you have another PC, you can try setting up a delphi installation there and compile it on that machine. that will give you a machine to compare the existing one to, to easily find the environment differences ;)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
I have try using charles and this is what i got:

http://img341.imageshack.us/img341/552/screenshotcharleslk4.jpg
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
something is wrong there, because you shouldn't have gotten answer.py but checkcookie.

also, use the sequence tab instead because that one shows the exact sequence in which the requests were made.
I am not clear in whether you have done or not the debug as I explained and what are the results. looking in charles, sequence tab, you can look at every request and response and see the exact headers. you need to corsscheck those with my comments in source code and see which is the first page that doesn't send the required headers OR doesn't receive the required headers. then we will have a starting point for investigatin the issue ;)
0
 

Author Comment

by:DelphiHelpPlease
Comment Utility
Ok, i will do that as soon as i find time for it.
0
 
LVL 28

Expert Comment

by:ciuly
Comment Utility
ok. just let me know of your findings.
0
 
LVL 1

Expert Comment

by:Computer101
Comment Utility
Forced accept.

Computer101
EE Admin
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now