Avatar billede spil2vind Nybegynder
15. januar 2009 - 11:52 Der er 27 kommentarer og
1 løsning

Lave en client software som kan sende SMS via BiBob

Jeg skal have lavet en client som kan sende SMS beskeder via BiBob, som jeg har fået oplyst bruger soap, som ikke siger mig ret meget, men det kronning kan jeg forstå, så håber på lidt hjælp på området.
Avatar billede hrc Mester
15. januar 2009 - 12:10 #1
For at lave SOAP skal du have fat i en WSDL-fil. Den beskriver data og funktioner i kaldet. Med den kan du få Delphi til at autogenerere en unit til kaldet. Er WSDL'en i orden og er Delphien nyere end version 7, så er det en simpel operation.
Avatar billede hrc Mester
15. januar 2009 - 12:11 #2
Normalt ligger WSDL på samme adresse som SOAP-servicen, men det er noget som BiBob må kunne hjælpe dig med.
Avatar billede spil2vind Nybegynder
15. januar 2009 - 12:18 #3
Jeg har kigget en del igennem uden at forstå det, Kroning ville hjælpe med oplysninger omkring mit spørgsmål, så det håber jeg på :-)
Avatar billede kroning Nybegynder
15. januar 2009 - 12:33 #4
Jeg benytter Delphi 7, Indy 10.2.3 (TIdHTTP komponenten) og BiBoB´s SOAP funktioner som ses her: https://www.bibob.dk/SmsSender.asmx

Jeg lavede det ret hurtig og kendte intet til SOAP og havde ikke lige tid til at sætte mig ind i det så det kan helt sikkert laves meget bedre.

Først nogle types og consts:

type
  TSOAP_Message_Type =  (SOAP_Login, SOAP_GetBalance, SOAP_GetNumbers, SOAP_GetPricePlan, SOAP_GetRemoteContacts, SOAP_SendMessage, SOAP_ScheduleMessage);
.
.
  SOAP_Std_CellPass = '<cellphone></cellphone><password></password>';
  SOAP_Login_XML = '<Login xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'</Login>';
  SOAP_GetBalance_XML = '<GetBalance xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'</GetBalance>';
  SOAP_GetNumbers_XML = '<GetNumbers xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'</GetNumbers>';
  SOAP_GetPricePlan_XML = '<GetPricePlan xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'</GetPricePlan>';
  SOAP_GetRemoteContacts_XML = '<GetRemoteContacts xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'</GetRemoteContacts>';
  SOAP_SendMessage_XML = '<SendMessage xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'<smsTo></smsTo><smscontents>string</smscontents><fromNumber></fromNumber></SendMessage>';
  SOAP_ScheduleMessage_XML = '<ScheduleMessage xmlns="http://www.bibob.dk/">'+SOAP_Std_CellPass+'<smsTo></smsTo><smscontents></smscontents><fromNumber></fromNumber><sendDate></sendDate></ScheduleMessage>';
.
.
var
  SOAP_Send_XML : string;
.
.

Selve kommunukationen med bibob har jeg lavet i en tråd:

  TSOAPThread = class(TThread)
  private
    { Private declarations }
        pResultElement, pBody : string;
    Result, FullResult : string;
    IdHTTP: TIdHTTP;
    IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;

    procedure SetResult;
  protected
    procedure Execute; override;
  public
    SOAP_Message_Type : TSOAP_Message_Type;
    constructor Create(Body, ResultElement : string; SOAP_Message_Type : TSOAP_Message_Type);
//    destructor Destroy; override;
  end;

// ****************************** TSOAPThread START ****************************************************************

constructor TSOAPThread.Create(Body, ResultElement : string; SOAP_Message_Type : TSOAP_Message_Type);
begin
    inherited Create(False);
    FreeOnTerminate:=true;

    pResultElement:=ResultElement;
  pBody:=Body;
  Self.SOAP_Message_Type:=SOAP_Message_Type;
end;

procedure TSOAPThread.SetResult;
var
  i,b : integer;
begin
  b:=Length(pResultElement);
  i:=Pos(pResultElement,Result);
  if i=0 then
  begin
    pResultElement:=Copy(pResultElement,1,b-1)+' />'; // f.eks. <LoginResult />
    i:=Pos(pResultElement,Result);
  end;

  if i=0 then
    Result:='ERR2'
  else
  begin
    Insert('/',pResultElement,2); //</LoginResult>
    Result:=Copy(Result,i+b,Pos(pResultElement,Result)-i-b);
  end;

// dette returneres hvis rssultat er tomt
//<LoginResult /></LoginResponse><
end;

procedure TSOAPThread.Execute;
var
  aStream: TMemoryStream;
  Params: TMemoryStream;
const
  SOAP_Top_XML = '<?xml version="1.0" encoding="utf-8"?><soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"><soap12:Body>';
  SOAP_Bottom_XML = '</soap12:Body></soap12:Envelope>';
begin
  aStream := TMemoryStream.create;
  Params := TMemoryStream.Create;

  IdHTTP:=TIdHTTP.Create;
  IdSSLIOHandlerSocketOpenSSL:=TIdSSLIOHandlerSocketOpenSSL.Create;
  IdSSLIOHandlerSocketOpenSSL.SSLOptions.Method:=sslvSSLv23;
  IdHTTP.IOHandler:=IdSSLIOHandlerSocketOpenSSL;

  IdHTTP.HTTPOptions:=[hoKeepOrigProtocol,hoForceEncodeParams];
  IdHTTP.Request.ContentType:='application/soap+xml; charset=utf-8';

  IdHTTP.Request.Host:='www.bibob.dk';
  pBody:=SOAP_Top_XML+pBody+SOAP_Bottom_XML;

  IdHTTP.Request.ContentLength:=Length(pBody);

  Params.Write(pBody[1],length(pBody));

  Result:='';
  try
    IdHTTP.ReadTimeout:=5000;
    IdHTTP.Post('https://www.bibob.dk/SmsSender.asmx', Params,aStream);
    aStream.Position:=0;
    SetLength(Result, aStream.Size);
    aStream.ReadBuffer(Pointer(Result)^, aStream.Size);
    FullResult:=Result;
  except
    Result:='ERR';
  end;

  aStream.Free;
  Params.Free;

  IdSSLIOHandlerSocketOpenSSL.Free;
  IdHTTP.Free;

  if Result<>'ERR' then
    SetResult;
end;

// ****************************** TSOAPThread SLUT ****************************************************************

Trådens OnTerminate procedure..

procedure TMainForm.SOAPOnTerminate(Sender: TObject);
var
  Result, FullResult : string;
  SOAP_Message_Type : TSOAP_Message_Type;
  ResultCode : integer;
  ErrorString : string;
begin
  Result:=(Sender as TSOAPThread).Result;
  FullResult:=(Sender as TSOAPThread).FullResult;

  ResultCode:=StrToIntDef(GetXMLBlok(Result,'<ResultCode>'),0);
  ErrorString:=GetXMLBlok(Result,'<ErrorString>');
//  <ResultCode>0</ResultCode><ErrorString>Ingen fejl.</ErrorString>

  SkrivDebugLog(FullResult,false);

  SOAP_Message_Type:=(Sender as TSOAPThread).SOAP_Message_Type;

  if (Result='ERR') or (result='ERR2') then
  begin
    SetStatusText('FEJL: '+Result,1,0);
    exit;
  end;

  if SOAP_Message_Type=SOAP_Login then
  begin
    if Result<>'' then
    begin
      LoginStatus:=0;
      SetStatusText('FEJL ved check af mobilnummer og adgangskode: '+Result,1,0);
    end
    else
    begin
      LoginStatus:=2;
      SetStatusText('Mobilnummer og adgangskode er i orden',2,5);
            CheckSaldo;
      GetNumbers;
      GetPricePlan;
    end;
  end;

osv. med resten af SOAP_Message_Type´erne
.
.
Min "Logon" procedure ser således ud:

procedure TMainForm.Logon;
begin
  if not IsMobilnummerOgAdgangskodeValid then
    exit;

  SOAP_Send_XML:=SOAP_Login_XML;
  SetXML_Nummer_Kode;
  LoginStatus:=1;

  SetStatusText('Tester mobilnummer og adgangskode',1,0);
  OpretSOAPThread(SOAP_Send_XML, '<LoginResult>', SOAP_Login);
end;
.
.
Og så de funktioner der bruges:
procedure TMainForm.SetXML_Nummer_Kode;
var
  Mobilnummer : string;
  Adgangskode : string;
begin
  GetMobilNummerOgAdgangskode(Mobilnummer,Adgangskode);
  SetXMLValue('<cellphone>',SOAP_Send_XML,Mobilnummer);
  SetXMLValue('<password>',SOAP_Send_XML,Adgangskode);
end;

Jeg har mobil nummer og koden (MD5) gemt i en ini fil:
procedure TMainForm.GetMobilnummerOgAdgangskode(var Mobilnummer, Adgangskode : string);
begin
  Mobilnummer:=SystemIni.ReadString(SystemIni_Sec,EditMobilnummer.Hint,'');
  Adgangskode:=SystemIni.ReadString(SystemIni_Sec,EditAdgangskode.Hint,'');
end;

Proceduren der indsætter værdier:
procedure TMainForm.SetXMLValue(Element : string; var XML : string; Value : string);
var
  i,x : integer;
  EndTag : string;
begin
  i:=Pos(Element,XML);
  if i=0 then
    exit;

  EndTag:=Element;
  Insert('/',EndTag,2);
  x:=Pos(EndTag,XML);
  if x=0 then
    exit;

  i:=i+Length(Element);
  Delete(XML,i,x-i); // fjerner en evt. tekst der allerede står der

  Insert(Value, XML, i);
end;

Og så proceduren der opretter "SOAP" tråden:
procedure TMainForm.OpretSOAPThread(Body, ResultElement: string;
  SOAP_Message_Type: TSOAP_Message_Type);
begin
  SkrivDebugLog(Body,true);
  TSOAPThread.Create(Body, ResultElement, SOAP_Message_Type).OnTerminate:=SOAPOnTerminate;
end;
Avatar billede kroning Nybegynder
15. januar 2009 - 12:38 #5
Husk at hente OpenSSL dll´erne som du kan finde et link til på Indy´s side.
Avatar billede hrc Mester
15. januar 2009 - 12:39 #6
Det bedste var at generere unitten selv på grundlag af WSDL-filen. Den burde være (halv)offentlig. Du skal nok bare kontakte BiBob. Desværre bruger du D7 som ikke genererer særlig gode unitter. Jeg har oplevet autogenereringen i D7 som fejlbehæftet, mens nyere versioner genererede fine filer.
Avatar billede kroning Nybegynder
15. januar 2009 - 12:41 #7
Det blev jo til en længere smører og der er en del kald til procedurer som jeg ikke har taget med men navnene siger vel hvad de skal bruges til.
Avatar billede kroning Nybegynder
15. januar 2009 - 12:43 #8
WSDL filen, er det ikke denne:
https://www.bibob.dk/SmsSender.asmx?WSDL
Avatar billede spil2vind Nybegynder
15. januar 2009 - 12:48 #9
Ja, jeg tror helt sikkert det sætter mig igang, men har lige kigget efter den OpenSSL hos indy uden held, den skal vel indeholde IdSSLIOHandlerSocketOpenSSL
Avatar billede spil2vind Nybegynder
15. januar 2009 - 13:52 #10
Sorry, ingen grund til at lede efter OpenSSL, den ligger i delphi 2009 Indy
Avatar billede kroning Nybegynder
15. januar 2009 - 14:04 #11
Nyeste (tror jeg) findes her:
http://indy.fulgan.com/SSL/openssl-0.9.8j-i386-win32.zip

fra 8. januar 2009, hvis du bruger en for gammel version af dll´erne vil det ikke virker, ligesom det heller ikke vil virker hvis din version af Indy er for gammel, der var vist en fejl i tidligere versioner der gjorde at det ikke virkede med SSL.

Men ellers burde du have hvad der skal til for at sende og modtage fra BiBoB, hvis du f.eks. vil have saldoen på din konto er det blot at skrive:

procedure TMainForm.CheckSaldo;
begin
  SOAP_Send_XML:=SOAP_GetBalance_XML;
  SetXML_Nummer_Kode;
  SetStatusText('Henter saldo',2,0);
  OpretSOAPThread(SOAP_Send_XML, '<GetBalanceResult>', SOAP_GetBalance);
end;

og så behandle resultatet i SOAPOnTerminate proceduren.

Men måske skulle du kikke på det som hrc nævner da du benytter Delphi 2009.
Avatar billede spil2vind Nybegynder
15. januar 2009 - 14:13 #12
Det med WSDL, har jeg ingen ide om hvordan jeg skal anvende det
Avatar billede spil2vind Nybegynder
15. januar 2009 - 16:41 #13
Jeg har fået kigget en del på det og har 2 spørgsmål

1)Params.Write(pBody[1],length(pBody));
  Dette virker ikke i D9, kan det ikke gøres anderledes?
2)ResultCode:=StrToIntDef(GetXMLBlok(Result,'<ResultCode>'),0);
  Hvad giver GetXMLBlok? eller sagt på en anden måde, hvordan ser funktion ud
Avatar billede kroning Nybegynder
15. januar 2009 - 17:25 #14
1) Jeg er aldrig nået længere end til D7 så det kan jeg ikke svare på.

2) Mht. "<ResultCode>" så er BiBoB vist ikke nået længere end til at den kun benyttes i funktionen GetPricePlan som en nem måde at få en fejl kode på hvor 0=ingen fejl.


function TMainForm.GetXMLBlok(XML, BlokTag : string) : string;
var
  i,x : integer;
begin
  Result:='';
  i:=Pos(Bloktag,XML);

  if i=0 then
    exit;
  i:=i+Length(BlokTag);
  Insert('/',BlokTag,2);
  x:=PosEx(Bloktag,XML,i);
  if x=0 then
    exit;

  Result:=Copy(XML,i,x-i);
end;
Avatar billede kroning Nybegynder
15. januar 2009 - 17:27 #15
Mht. 1), kan du sige om det er pBody[1] eller length(pBody) der giver problemer?
Avatar billede kroning Nybegynder
15. januar 2009 - 17:29 #16
funktionen PosEx som benyttes i GetXMLBlok findes i D7 i uniten StrUtils
Avatar billede spil2vind Nybegynder
15. januar 2009 - 17:29 #17
[DCC Error] UnitBiBob1.pas(125): E2014 Statement expected, but expression of type 'Integer' found
Avatar billede spil2vind Nybegynder
15. januar 2009 - 17:33 #18
Har ikke umiddelbart kunne finde den nogen steder, kan du ikke klippe koden ud?
Avatar billede kroning Nybegynder
15. januar 2009 - 17:52 #19
1) Lyder som om Write funktionen i TMemoryStream har ændret sig, hvilke parametre vil funktionen have?

2) Jeg er helt sikker på at PosEx stadig findes i D9.

function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
var
  I,X: Integer;
  Len, LenSubStr: Integer;
begin
  if Offset = 1 then
    Result := Pos(SubStr, S)
  else
  begin
    I := Offset;
    LenSubStr := Length(SubStr);
    Len := Length(S) - LenSubStr + 1;
    while I <= Len do
    begin
      if S[I] = SubStr[1] then
      begin
        X := 1;
        while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do
          Inc(X);
        if (X = LenSubStr) then
        begin
          Result := I;
          exit;
        end;
      end;
      Inc(I);
    end;
    Result := 0;
  end;
end;
Avatar billede fundus Nybegynder
15. januar 2009 - 19:08 #20
Tænkte på om du fx kunne uploade den færdige kode med program vis det er muligt :)
Avatar billede spil2vind Nybegynder
15. januar 2009 - 21:41 #21
Jeg har ikke noget imod at lægge grund funktionerne ud, når jeg har dem færdige, der er dog en del tilbage, måske Kroning har lyst til frigive mere?

Kroning:med hensyn til Params.Write har parameterne
function Write(const Buffer; Count: Longint): Longint; override;

PosEx er der stadig:PosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
Avatar billede kroning Nybegynder
16. januar 2009 - 00:41 #22
Jeg har ikke noget imod at sende hele koden så post nogle mail addr. så sender jeg.
Jeg bruger kun en enkelt 3. parts komponent CoolTrayIcon, og så selv. Indy. Desuden en enkelt unit md5 til password.
Avatar billede kroning Nybegynder
16. januar 2009 - 00:51 #23
Jeg har ingen ideer mht. fejlen E2014.
Avatar billede spil2vind Nybegynder
16. januar 2009 - 07:15 #24
Er det smart at smide email adresser i dette forum?
Avatar billede kroning Nybegynder
16. januar 2009 - 08:22 #25
Det er der så mange der gør men de fleste skjuler den lidt ved at skrive f.eks. hans snabel a mail punktum dk
Avatar billede spil2vind Nybegynder
16. januar 2009 - 08:43 #26
Du kender jo min carsten snabel bjarlert.dk
Avatar billede kroning Nybegynder
16. januar 2009 - 20:17 #27
>spil2vind, jeg har sendt hele sourcen på mail.
Avatar billede kroning Nybegynder
17. januar 2009 - 14:18 #28
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester