Skocz do zawartości

[Delphi] Komponent Gadu-Gadu na licencji GPL


markovcd

Polecane posty

Po pierwsze, chciałem się przywitać bo to mój pierwszy post.

Po drugie, chciałem podzielić się z Wami napisanym przeze mnie komponentem do obsługi protokołu GG w wersji 8.0.

Napisałem go, ponieważ nie istnieje żadne dobre rozwiązanie dla Delphi (HGG jest przestarzałe, TGGLite płatne). Póki co jest to pierwsza publicznie dostępna wersja więc funkcjonalność skromna. Mam jednak zamiar poszerzyć ją, aby obsługiwała w pełni ten protokół.

 

Podstawowe funkcje:

  • Logowanie do sieci
  • Obsługa wszystkich rodzajów statusu (włącznie z "PoGGadaj ze mną" i "Nie przeszkadzać")
  • Wiadomości czystym tekstem, i przy odrobinie wysiłku, również formatowane
  • Konferencje - wysyłanie i otrzymywanie
  • Prosta w obsłudze lista użytkowników.
W przyszłości oczywiście planuję takie funkcje jak import/eksport listy, obsługa obrazków, zakładanie/usuwanie konta.

Komponent jest oparty na socketach.

 

Do pobrania tutaj:

http://s42939.zut.edu.pl/dev/articles.php?article_id=7

 

Lista zmian:

0.02 (22 stycznia 2010)

- Dodanie obsługi długich wiadomości

- Dodanie obsługi importu/eksportu listy kontaktów

- Poprawa kilku bugów

- Połączenie komponentów TEasyGG i TIdleTimer w jedną paczkę

 

Całość można pobrać także z 4programmers:

http://download.4programmers.net/TEasyGG

 

W tym temacie prosiłbym o zgłaszanie błędów i ewentualnych sugestii.

Link do komentarza
Udostępnij na innych stronach

Witaj markovcd, jesteśmy z tej samej uczelni! Cholera, tłoczno się tu robi ^^... Nieszczęsna Politechnika Szczecińska przemianowana na Zachodniopomorski Uniwersytet Technologiczny :<...>

soon Delphi will be only for veterans and finally we all will die at the end…

delphi.dathox.com - nowinki z świata Delphi/Pascala

only programmers and drug dealers call their customers "users"

 

Oto cisza przed burzą, Chwile się dłużą.Z gór schodzi dużo chmur ku podnóżom.Ptaki milaczą, drogi suche jak wiór się kurzą, Ptaki milczą a drogi się kurzą.

Link do komentarza
Udostępnij na innych stronach

HNB: to myślę że powinieneś się tymbardziej podzielić się modułem do ładowania dllki z zasobów. Ja wprawdzie kończyłem tylko

zaocznie studium policealne, ale jak się dowiaduje - tak jak Ty - jestem z Grodu Gryfa smile.gif A zionki powinni sobie pomagać raczej wink.gif

 

markovcd: komponent fajny, właśnie sobie pisze własnego klienta gg na bazie tego komponentu. Tylko nie bardzo wiem jak można

obslużyć dla dynamicznie tworzonego komponentu zdarzenie OnSendMsg. Mam taki kod jak poniżej i póki co problematyczną linijkę

dalem jako komentarz. Bo używam Twojego dema, ale komponent IdleTimer zlikwidowałem bo mi nie będzie potrzebny, a TEGG po

prosatu utworzyłem dynamicznie, bo póki co nie chcę dodawać tego komponentu do palety. Mam też sugestię aby w przyszłości, jak

się da - dorobił byś funkcję może pobierania kontaktów z serwera GG. Poza tym póki co błędów nie stwierdziłęm, potestuje jeszcze.

 

EGG := TEasyGG.Create(Self);
with EGG do
begin
ReceiveURLS := True;
FriendsOnly := False;
Port := 0;
UID := 0;
OnUserStatus := UserStatus;
OnReceiveMsg := ReceiveMsg;
// i w lini poniżej błąd
OnSendMsg := SendMsg(
OnLoginOK := LoginOK;
OnLoginFailed := LoginFailed;
OnConnecting := EGGConnecting;
OnDisconnect := EGGDisconnect;
end;

 

A błąd jest następujący:

 

KOD

 

 

[Error] main.pas(269): Incompatible types: 'Cardinal' and 'TNotifyEvent'

Pozdrawiam: olesio

Link do komentarza
Udostępnij na innych stronach

Witaj markovcd, jesteśmy z tej samej uczelni! Cholera, tłoczno się tu robi ^^... Nieszczęsna Politechnika Szczecińska przemianowana na Zachodniopomorski Uniwersytet Technologiczny :<...>

 

 

 

 

No serio, sporo nas tu :x.

 

Co do tematu:

Dzieci beda mialy podstawke do uprzykrzania zycia innym smile.gif

"(2b || !(2b)) == question" W. Shakespeare

http://jakubniwa.pl - świat sztucznej inteligencji

Link do komentarza
Udostępnij na innych stronach

Markovcd: Zainteresuj się libgadu. Biblioteka do obsługi protokołu dostępna na licencjach GPL i LGPL

 

 

 

Komponenta pisałem właśnie wg. specyfikacji twórców libgadu (http://toxygen.net/libgadu/protocol/).

Pierwotnie miałem zamiar zrobić builda pod windowsa tejże biblioteki i zrobić import do Delphi. Jednak odpadłem już przy próbie kompilacji pod cygwin. smile.gif

 

BTW. Dokumentacja jest już dostępna na stronie.

Link do komentarza
Udostępnij na innych stronach

wywala mi masę errorów gdy próbuję dodać komponent

KOD[Error] EGGBase.pas(67): ',' or ':' expected but '(' found

[Error] EGGBase.pas(68): Invalid compiler directive: 'private'

[Error] EGGBase.pas(74): Method 'Event' not found in base class

[Error] EGGBase.pas(108): Cannot override a static method

[Error] EGGBase.pas(126): Incompatible types

[Error] EGGBase.pas(129): Incompatible types: 'TComponent' and 'TEasyGGBase'

[Error] EGGBase.pas(140): Undeclared identifier: 'Active'

[Error] EGGBase.pas(219): Not enough actual parameters

[Error] EGGBase.pas(363): Not enough actual parameters

[Error] EGGBase.pas(406): Declaration of 'TGGSocket' differs from previous declaration

[Error] EGGBase.pas(408): This form of method call only allowed in methods of derived types

[Error] EGGBase.pas(409): Undeclared identifier: 'FClientSocket'

[Error] EGGBase.pas(410): Undeclared identifier: 'InitSocket'

[Error] EGGBase.pas(413): Declaration of 'TGGSocket' differs from previous declaration

[Error] EGGBase.pas(415): Undeclared identifier: 'FClientSocket'

[Error] EGGBase.pas(415): Missing operator or semicolon

[Error] EGGBase.pas(416): This form of method call only allowed in methods of derived types

[Error] EGGBase.pas(419): Identifier redeclared: 'TGGSocket'

[Error] EGGBase.pas(421): Undeclared identifier: 'Value'

[Warning] EGGBase.pas(421): Comparing signed and unsigned types - widened both operands

[Error] EGGBase.pas(423): 'THEN' expected but identifier 'Connected' found

[Error] EGGBase.pas(431): Undeclared identifier: 'Result'

[Error] EGGBase.pas(431): Missing operator or semicolon

[Error] EGGBase.pas(436): Statement expected but 'CONSTRUCTOR' found

[Error] EGGBase.pas(450): Undeclared identifier: 'Socket'

[Error] EGGBase.pas(49): Unsatisfied forward or external declaration: 'TGGSocket.DoActivate'

[Error] EGGBase.pas(50): Unsatisfied forward or external declaration: 'TGGSocket.GetClientType'

[Error] EGGBase.pas(53): Unsatisfied forward or external declaration: 'TGGSocket.Create'

[Error] EGGBase.pas(54): Unsatisfied forward or external declaration: 'TGGSocket.Destroy'

[Error] EGGBase.pas(90): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGWelcome'

[Error] EGGBase.pas(92): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGLoginOK'

[Error] EGGBase.pas(93): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGLoginFailed'

[Error] EGGBase.pas(94): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGDisconnecting'

[Error] EGGBase.pas(95): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGNotifyReply'

[Error] EGGBase.pas(96): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGStatus'

[Error] EGGBase.pas(97): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGSendMsgAck'

[Error] EGGBase.pas(98): Unsatisfied forward or external declaration: 'TEasyGGBase.SocketGGRecvMsg'

[Fatal Error] EGG.pas(29): Could not compile used unit 'EGGBase.pas'

 

Podświetla TEasyGGBase = class abstract(TGGSocket)

Link do komentarza
Udostępnij na innych stronach

egg.OnSendMsg := eggSendMsg; // nie ma błędu

 

No niestety ja u siebie mam taki błąd jak podałem wcześniej, ale olać

akurat nie potrzebuje potwierdzenia że wiadomość doszła i do testoó

wystarcza mi InfoBot póki co smile.gif A linię ze stałą do pingów poprawiłem

Pozdrawiam: olesio

Link do komentarza
Udostępnij na innych stronach

HNB: to myślę że powinieneś się tymbardziej podzielić się modułem do ładowania dllki z zasobów. Ja wprawdzie kończyłem tylko

 

zaocznie studium policealne, ale jak się dowiaduje - tak jak Ty - jestem z Grodu Gryfa smile.gif A zionki powinni sobie pomagać raczej wink.gif

 

 

Pamiętam, czas odpowiedzi upłynął, jako, że unit był cały czas za darmo dostępny co za różnica czy go udostępnię dalej? Notki i tak są bardzo ok - do użytku komercyjnego i darmowego smile.gif. Lada dzień dam na swoim blogu jako news. stay tuned - nie chcę dawać suchego unitu bez opisu.

 

@markovcd - nie ma sensu używać w takim komponencie składni z Delphi nowszego niż Delphi 6, zwłaszcza, że wycofano wszystkie nowsze darmowe wersje, a najwięcej ludzi i tak bazuje na D6/7...

soon Delphi will be only for veterans and finally we all will die at the end…

delphi.dathox.com - nowinki z świata Delphi/Pascala

only programmers and drug dealers call their customers "users"

 

Oto cisza przed burzą, Chwile się dłużą.Z gór schodzi dużo chmur ku podnóżom.Ptaki milaczą, drogi suche jak wiór się kurzą, Ptaki milczą a drogi się kurzą.

Link do komentarza
Udostępnij na innych stronach

markovcd: a mi się wydaje że znalazłem jakiś błąd jednak. Myślałem że to wina mojego kodu, ale użyty w Demie przy

dynamicznym tworzeniu TEasyGG również się pokazuje. Pracuje pod Delphi 7 Personal o ile to ma jakieś w usuwaniu

buga dla Ciebie znaczenie. Mianowićie przeanalizuj kod i exeka ktore wrzuciłem pod poniższy adres. Zobacz kod dla

przycisku o Captionie Importuj kontakty. Mianowicie kiedy dokona się importu przy połączonym EGG (status inny niż

"Niedostępny" to wrzystko jest ok i lista się wypełnia. Natomiast jeżeli zainportujemy listę przy użyciu mojego kodu,

a dopiero po tym połączymy się z serverem ustawiając status na inny niż Niedostępny to program wysypie się pod

IDE z komunikatem o następującej treśćii. Dodam, że nie dzieje się to dla całego pliku z kontaktami, który został w

Gadu-Gadu (używam sporadyznie dlatego mam wersję 7.6.0, bo mi wystarcza). Jak chcesz mogę podeśłac Tobie na

PW linka z moim plikiem z kontaktami. Ale myślę że błąd jest gdzieś po stronie EasyGG, bo jak jestem połączony w

momencie importu listy to wszystko jest ok. Co ciekawe IDE wywala się na module EGGBase podświetlając ostatnią

linijkę przed endem; Ja nie znam się na socketach więc nie wiem jak mogę to samodzielnie poprawić. Prosiłbym o

pomoc i odpowiedź, bo póki tego nie przeskoczę to nie skończe swojego komunikatora do końca tak by działał ok.

Przy okazji chciałem Wam wszystkim życzyć już teraz zdrowych i wesołyh Świąt oraz szcześliwego Nowego Roku.

 

Na PW podesłałem Tobie link do pliku z moimi kontaktami. Próbowałem analizować plik wycinając tylko fragmenty

i zapisując pod inną nazwą. I czasem się wczytała cała lista bez błedu, ale nie wiem czy to wina jakiegoś wpisu w

jednej z linijek pliku czy też wina jest w obsłudze Socketów przez Twój komponent. To czekam na odpowiedź ;/

 

Komunikat:

KOD

Project project1.exe raised exception class EAccessViolation with message 'Naruszenie praw dostępu pod adresem

00402909 w module 'project1.exe'. Czytanie adresu 649DDCEE'. Process stopped. Use Step or Run to continue.

 

Miejsce w kodzie gdzie "ląduje" IDE:

procedure TEasyGGBase.SocketRead(Sender: TObject; Socket: TCustomWinSocket);
var
 gg_header: Tgg_header;
 PData: ^Byte;
begin
 PData := Addr(Socket.ReceiveText[1]); // odebranie pakietu
 Move(PData^, gg_header, SizeOf(gg_header)); // odzielenie naglowka
 Inc(PData, SizeOf(gg_header)); // zwiększenie wskaźnika o rozmiar nagłówka
 PacketHandler(gg_header.typ, gg_header.length, PData^); // funkcja obslugujaca wszystkie rodzaje pakietow <-- ta linia się podświetla
end;

 

Kod źródlowy:

KOD

http://www.speedyshare.com/files/19934724/egg_problem.rar

 

Pozdrawiam: olesio

Link do komentarza
Udostępnij na innych stronach

Lepiej napisz sobie program w taki sposób aby przechowywać dane w ListView.

Niech Caption to będzie nazwa użytkownika a SubItems[0] (druga kolumna) to

bedzie numer GG. Poniższa metoda zapisuje do pliku spakowanego zlibem, tak

więc do uses należy dodać moduł zLib. Jeżeli nie chcesz pakowac/rozpakować

pliku to po prostu z kodu usuń funkcję pakującą oraz rozapkowująca plik, a ja

zapisuje w pliku typowanym, chyba najprościej jest tak. Innego sposobu jakoś

nie znam. Mozna jeszcze użyć xmla lub plików ini ale taki sposób imo jest ok.

Chociaż jeżeli chcesz koniecznie zapisywać przy użyciu ListBoxa z kodu. który

dołączony jest do komponentu - to zapisuj taki rekord jak podałem - tylko że

Name oraz Uid odczytuj z TUser(lstContacts.Items.Objects).Name i ...UID.

 



public

//...

procedure PackMemStream(var MemoryStream : TMemoryStream);

function UnpackMemStream(var MemoryStream : TMemoryStream) : boolean;

procedure LoadContacts(FileName : string);

procedure SaveContacts(FileName : string);

// ...

end;



type

TUserRecord = record

Name : string[30];

UID : LongWord;

end;



var

CtxRec : TUserRecord;

MainForm : TMainForm;



procedure TMainForm.PackMemStream(var MemoryStream : TMemoryStream);

var

I : integer;

PStrm : Pointer;

begin

CompressBuf(MemoryStream.Memory, MemoryStream.Size, PStrm, I);

MemoryStream.Clear;

MemoryStream.Write(PStrm^, i);

end;



function TMainForm.UnpackMemStream(var MemoryStream : TMemoryStream) : boolean;

var

PStrm : Pointer;

I, Tmp : integer;

begin

Tmp := 0;

Result := False;

if MemoryStream.Size = 0 then

begin

Exit;

end;

try

DecompressBuf(MemoryStream.Memory, MemoryStream.Size, Tmp, PStrm, I);

MemoryStream.Clear;

MemoryStream.Write(PStrm^, I);

MemoryStream.Position := 0;

except

MessageBox(Application.Handle, 'Nieprawidłowy format pliku z kontaktami!',

PChar(Application.Title), MB_OK + MB_ICONERROR);

Exit;

end;

Result := True;

end;



procedure TMainForm.LoadContacts(FileName : string);

var

S : string;

User : TUser;

I, Cnt : Integer;

MS : TMemoryStream;

ListItem : TListItem;

begin

if FileExists(FileName) = False then

begin

Exit;

end;

MS := nil;

try

MS := TMemoryStream.Create;

MS.LoadFromFile(FileName);

if UnpackMemStream(MS) = False then

begin

Exit;

end;

Cnt := MS.Size div SizeOf(TUserRecord);

for I := 0 to Cnt - 1 do

begin

MS.Read(CtxRec, SizeOf(TUserRecord));

User := EGG.Users[EGG.AddUser(CtxRec.UID)];

User.Name := CtxRec.Name;

S := IntToStr(StateID(User.Status));

ContactsLV.AddItem(User.Name, User);

ListItem := ContactsLV.Items[ContactsLV.Items.Count - 1];

ListItem.SubItems.Add(IntToStr(User.UID));

ListItem.SubItems.Add(User.Description);

ListItem.SubItems.Add(S);

end;

except

MessageBox(Application.Handle, PChar('Nie można wczytać kontaktów z pliku: ' +

FileName + '!'), PChar(Application.Title), MB_OK + MB_ICONERROR);

end;

MS.Free;

end;



procedure TMainForm.SaveContacts(FileName : string);

var

I, Cnt : Integer;

MS : TMemoryStream;

begin

MS := nil;

Cnt := ContactsLV.Items.Count;

try

MS := TMemoryStream.Create;

for I := 0 to Cnt - 1 do

begin

CtxRec.Name := ContactsLV.Items[i].Caption;

CtxRec.UID := StrToInt(ContactsLV.Items[i].SubItems[0]);

MS.Write(CtxRec, SizeOf(CtxRec));

end;

except

MessageBox(Application.Handle, PChar('Nie można zapisać kontaktow do pliku: ' +

FileName + '!'), PChar(Application.Title), MB_OK + MB_ICONERROR);

end;

PackMemStream(MS);

MS.SaveToFile(FileName);

MS.Free;

end;

Pozdrawiam: olesio

Link do komentarza
Udostępnij na innych stronach

No męcze już te kontakty tyle czasu i z tym Twoim kodem i nie mogę sobie poradzić. Zawsze z Listą kontaktów mam problem .

Nie można jakoś krótko i prosto?

albo wczytać z serwera?

tak jak w tym demku jest OK tylko właśnie za każdym razem przecież nie będę wpisywać

Link do komentarza
Udostępnij na innych stronach

Davai: import z oraz eskport do serwera kontaktów, z tego co pisał markovcd jest planowany w

następnej wersji komponentu. Ale zapisanie i odczyt do pliku póki co nie jest problemem, robisz

to tak jak pokazałem. A jeżeli chodzi Tobie o importowanie z pliku to możesz to zrobić tak jak ja

to zrobiłem - kod poniżej. Plik w formacie takim jaki obsluguje GG 7.6.0, bo nowszego nie mam

zamiaru używać za bardzo. Do funkcji przekazuje się jako parametr konkretną linijkę z pliku txt

z kontaktami. Także trzeba wczytac plik do StringList na przykład i w pętli przekazać do funkcji

linijki, a ona zwróci rekord w ostaci wyświetlany nick (po 3cim separatorze i numer (po 6tym).

Separatorem jest jak widać średnik. Może da się to zrobić szybciej/prościej, ale ja zrobiłem to

w taki sposób jaki potrafię, żeby działało. Nie jestem ekspertem, tylko programistą amatorem.

// ...
type
 TUserObject = class(TObject)
   Name : string[30];
   UID : LongWord;
 end;
//...
function Extract_GG_Num(const LineOfText : string) : TUserRecord;
const
 NickDispAfterSep = 3;
 NumAfterSep = 6;
 Separator = ';';
var
 I, SepCnt : integer;
 S : string;
begin
 Result.Name := '';
 Result.UID := 0;
 if LineOfText = '' then
   Exit;
 SepCnt := 0;
 for I := 1 to Length(LineOfText) do
 begin
   if LineOfText[I] = Separator then
     SepCnt := SepCnt + 1;
   if SepCnt = NickDispAfterSep then
     Break;
 end;
 if SepCnt < NickDispAfterSep then
   Exit;
 S := Copy(LineOfText, I + Length(Separator), MaxInt);
 for I := 1 to Length(S) do
 begin
   if S[I] = Separator then
   begin
     Delete(S, I, MaxInt);
     Break;
   end;
 end;
 Result.Name := S;
 SepCnt := 0;
 for I := 1 to Length(LineOfText) do
 begin
   if LineOfText[I] = Separator then
     SepCnt := SepCnt + 1;
   if SepCnt = NumAfterSep then
     Break;
 end;
 if SepCnt < NumAfterSep then
   Exit;
 S := Copy(LineOfText, I + Length(Separator), MaxInt);
 for I := 1 to Length(S) do
 begin
   if S[I] = Separator then
   begin
     Delete(S, I, MaxInt);
     Break;
   end;
 end;
 Result.UID := StrToInt64(S);
end;

Pozdrawiam: olesio

Link do komentarza
Udostępnij na innych stronach

Współczuję... Tyle niepotrzebnej roboty. Już lepiej porządny protokół wspierać i to taki, do którego są porządne serwery :]

Normalnie nigdy bym nie zajął się takim śmieciem, jakim jest GG. Nawet nie wiesz ile niecenzuralnych słów padło przy analizie i implementacji tego. Napisałem ten komponent bo chcę go użyć w swoim kliencie Gadu-Gadu - może nawet uda mi się zebrać trochę osób do pomocy. Ma to być program podobny do Konnekta, który niestety już nie jest aktualizowany.

 

Mały updejt:

Obecnie jestem na etapie pisania obsługi listy kontaktów - pełne wsparcie dla formatu jaki jest w GG8. Mianowicie import/eksport z serwera i pliku.

Prace się trochę opóźnią ze względu na święta i niedawną awarię mojego dysku.

Link do komentarza
Udostępnij na innych stronach

Gratuluję dobrej roboty! :D

 

A czy jest już wsparcie dla awatarów?

 

EDIT

Jeżeli nie, to mogę pomóc. :) Szybka anliza pozwoliła mi zauważyć, że korzystając z protokołu HTTP możemy w prosty sposób pobrać awatar dowolnego użytkownika. :)

Wystarczy pobrać obraz ze strony http://avatars.gadu-gadu.pl/big/[numer_gg] (duża wersja) lub http://avatars.gadu-gadu.pl/small/[numer_gg] (mała wersja). Jeżeli strona zwróci pusty dokument lub błąd 404, oznacza to, że użytkownik nie ma przypisanego awataru i można użyć jakiegoś domyślnego.

 

Sądzę, że można to potestować i ewentualnie dorzucić do komponentu. Przyda się z pewnością.

 

A tak nawiasem mówiąc, popieram inicjatywę z reaktywacją Konnekta. Sam używałem go przez cały okres mojej aktywności w sieci i niestety niedawno zostałem zmuszony do przejścia na "Nowe GG". Oby projekt ruszył i był równie godny, co sam Konnekt.

Link do komentarza
Udostępnij na innych stronach

markovcd: fajnie że dodasz nowe features. A czy jak się uporasz z zaginionymi danymi z dysku

to sprawdzisz mój kod w archiwum egg_problem.rar tak jak opisywałem oraz listę kontkatów co

przesłalem Tobie na PW? Bo co ciekawe jak robiłem testy w pętli dodając użytkowników w tym

komunikatorze co go teraz pisze i jak nazwę usera podawałem to co z pliku a jako numer dalem

losową liczbę do maksymalnego zakresu typu LongWord to wszystko było ok, także wynika że to

jest problem z którymś z numerów gg _CHYBA_, ale nie wiem z ktorym. A i co ciekawe jeszcze

to niszczenie komponentu przy rozłączeniu oraz ponowne towrzenie go dynamiczne przy łączeniu

nic nie pomogło dalej sięwysypuje tak jak opisałem. Fajnie jakbyś doszedł co i dlaczego u mnie

takie "kwiatki" powoduje i naprawił to w następnej wersji komponentu, bo ja sam to nie dojdę ;/

Pozdrawiam: olesio

Link do komentarza
Udostępnij na innych stronach

Zarchiwizowany

Ten temat jest archiwizowany i nie można dodawać nowych odpowiedzi.

×
×
  • Utwórz nowe...