Potrafiąc już masowo wysyłać jedną wiadomość pod kilka wcześniej zapisanych w pliku tekstowym numerów możemy z dużym powodzeniem poinformować w bardzo szybki i wygodny sposób naszych znajomych o jakimś wydarzeniu.
Co jednak, jeśli tą wiadomość zechcemy wysłać do całego miasta, aby poinformować wszystkich jego mieszkańców o jakiejś uroczystości? W takiej sytuacji z pomocą może nam przyjść katalog publiczny, dzięki któremu wyszukamy interesujące nas osoby na podstawie imienia, pseudonimu, płci, czy też miasta.
W examplach libgadu nie znajdziemy programu łączącego się z katalogiem publicznym, zatem musimy napisać go sami od podstaw. Przed przystąpieniem do pisania kodu wypadałoby zaznajomić się z strukturą katalogu publicznego. Jak widać otrzymujemy prawie, że gotowca z strony projektu. Jedyne co musimy zrobić to wyeliminować zabezpieczenie anty script kiddle oraz dopisać kilka linijek.
Najważniejsze rzeczy, na które należy zwrócić uwagę to:
- Struktura sesji (gg_login_params)
- Strultura zdarzenia (gg_event)
- Zdarzenie GG_EVENT_PUBDIR50_SEARCH_REPLY
- Wysłanie listy kontaktów przy pomocy funkcji gg_notify(), aby móc komunikować się z serwerem
- Optymalizacja kodu pod kątem odbierania „paczek” danych, ale tym zajmiemy się na końcu
Najsampierw sklepmy to, co już mamy wyłożone na tacy 🙂
/*
Program łączy się z katalogiem
Publicznym i pobiera dane.
Autor:
Komeniusz [Nie odpowiadam za użycie tego programu!]
Licencja: GNU - edukacyjna!
Program testowano na:
System: Ubuntu 9.10
Biblioteka: Libgadu 1.9.0-rc2 (wersja testowa)
Download Libgadu: http://toxygen.net/libgadu/
Dokumentacja Libgadu: http://toxygen.net/libgadu/doc/
*/
//Niezbędne biblioteki
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "libgadu.h"
int main(int argc, char **argv) {
if(argc < 3) {
printf("Użycie: %s <numer> <hasło>n", argv[0]);
return 1;
}
//Nasze strukturki
struct gg_session *sesja;
struct gg_event *event;
struct gg_login_params p;
gg_debug_level = 0;
memset(&p, 0, sizeof(p));
p.uin = atoi(argv[1]);
p.password = argv[2];
p.encoding = GG_ENCODING_UTF8;
if(!(sesja = gg_login(&p))) {
printf("Nie udało się połączyć: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
//Tworzymy nowe zapytanie do serwera
gg_pubdir50_t zapytanie;
zapytanie = gg_pubdir50_new(GG_PUBDIR50_SEARCH_REQUEST);
if(!zapytanie) {
printf("Brak pamięci");
}
//Wypełniamy pola zapytania do wyszukiwania w katalogu
//Struktura ogólna - gg_pubdir50_add(zapytanie, pole, "wartość");
//Zaczynamy od numeru - 0
gg_pubdir50_add(zapytanie, GG_PUBDIR50_START, "0");
//Przeszukiwanie według imienia - Anna
gg_pubdir50_add(zapytanie, GG_PUBDIR50_FIRSTNAME, "Anna");
//Żądana płeć - kobieta
gg_pubdir50_add(zapytanie, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_FEMALE);
//Osoby aktualnie dostępne
gg_pubdir50_add(zapytanie, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE);
//Wszystkie rodzaje pól zapytań
/*
GG_PUBDIR50_UIN Numer Gadu-Gadu.
GG_PUBDIR50_STATUS Status (tylko wynik wyszukiwania).
GG_PUBDIR50_FIRSTNAME Imię.
GG_PUBDIR50_LASTNAME Nazwisko.
GG_PUBDIR50_NICKNAME Pseudonim.
GG_PUBDIR50_BIRTHYEAR Rok urodzenia lub przedział lat oddzielony spacją.
GG_PUBDIR50_CITY Miejscowość.
GG_PUBDIR50_GENDER Płeć.
GG_PUBDIR50_GENDER_FEMALE Kobieta.
GG_PUBDIR50_GENDER_MALE Mężczyzna.
GG_PUBDIR50_ACTIVE Osoba dostępna (tylko wyszukiwanie).
GG_PUBDIR50_ACTIVE_TRUE Wyszukaj tylko osoby dostępne.
GG_PUBDIR50_START Numer początkowy wyszukiwania (tylko wyszukiwanie).
GG_PUBDIR50_FAMILYNAME Nazwisko rodowe (tylko wysyłanie informacji o sobie).
GG_PUBDIR50_FAMILYCITY Miejscowość pochodzenia (tylko wysyłanie informacji o sobie).
*/
//Wykonujemy zapytanie
gg_pubdir50(sesja, zapytanie);
//Aby móc komunikować się z serwerem
//Wysyłamy pustą listę kontaktów
if(gg_notify(sesja, NULL, 0) == -1) {
printf("Polaczenie przerwane: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
while(1) {
if(!(event = gg_watch_fd(sesja))) {
printf("Polaczenie przerwane: %sn", strerror(errno));
gg_logoff(sesja);
gg_free_session(sesja);
return 1;
}
//Jeśli odebraliśmy odpowiedź od
//Katalogu publicznego
/*
GG_PUBDIR50_WRITE Wysłanie do serwera informacji o sobie.
GG_PUBDIR50_READ Pobranie z serwera informacji o sobie.
GG_PUBDIR50_SEARCH Wyszukiwanie w katalogu publicznym.
GG_PUBDIR50_SEARCH_REPLY Wynik wyszukiwania w katalogu publicznym.
*/
if(event->type == GG_EVENT_PUBDIR50_SEARCH_REPLY) {
gg_pubdir50_t wynik;
int i, ilosc;
wynik = event->event.pubdir50;
ilosc = gg_pubdir50_count(wynik);
if(ilosc < 1) {
printf("Nie znaleziono");
return;
}
//Wyciąganie informacji
for(i = 0; i < ilosc; i++) {
const char *numer, *imie, *pseudo, *urodzony, *miasto, *status;
numer = gg_pubdir50_get(wynik, i, GG_PUBDIR50_UIN);
imie = gg_pubdir50_get(wynik, i, GG_PUBDIR50_FIRSTNAME);
pseudo = gg_pubdir50_get(wynik, i, GG_PUBDIR50_NICKNAME);
urodzony = gg_pubdir50_get(wynik, i, GG_PUBDIR50_BIRTHYEAR);
miasto = gg_pubdir50_get(wynik, i, GG_PUBDIR50_CITY);
status = gg_pubdir50_get(wynik, i, GG_PUBDIR50_STATUS);
//Drukowanie informacji
printf("Numer: %snImię: %snPseudonim: %sn"
"Urodzony: %snMiejscowość: %sn",
numer, imie, pseudo, urodzony, miasto);
//Wyświetlamy status znalezionej osoby
switch((status) ? atoi(status) : -1) {
case GG_STATUS_AVAIL:
printf("Dostępnyn");
break;
case GG_STATUS_BUSY:
printf("Zajętyn");
break;
default:
printf("(?)n");
}
printf("n");
}
}
//Zwolnienie pamięci dla struktury zdarzenia
gg_event_free(event);
}
//Zwolnienie pamięci dla struktury sesji
gg_free_session(sesja);
//Zwolnienie pamięci dla zapytania i odpowiedzi serwera
gg_pubdir50_free(zapytanie);
return 0;
}
Program przyjmuje 2 parametry – numer i hasło. Jako wynik zwraca 20 numerów z katalogu publicznego, pasujących do naszego zapytania. Przykładowy wynik może wyglądać następująco
Numer: 1213***
Imię: Anna
Pseudonim: anna
Urodzony: (null)
Miejscowość: Łódź
ZajętyNumer: 2095***
Imię: Anna
Pseudonim: Anna
Urodzony: 1994
Miejscowość: (null)
DostępnyNumer: 496***
Imię: Anna
Pseudonim: (null)
Urodzony: 1977
Miejscowość: (null)
Zajęty[…]
Program zwraca jedynie 20 numerów, ponieważ serwer GG zwraca taką ilość po wykonaniu zapytania. Aby wyciągnąć z niego wszystkie wyniki pasujące do naszego zapytania należy wykonać kilka zapytań z zmieniającym się numerem sekwencyjnym od, którego będziemy kontynuować przeszukiwanie bazy danych.
/* Program łączy się z katalogiem Publicznym i pobiera dane. Autor: Komeniusz [Nie odpowiadam za użycie tego programu!] Licencja: GNU - edukacyjna! Program testowano na: System: Ubuntu 9.10 Biblioteka: Libgadu 1.9.0-rc2 (wersja testowa) Download Libgadu: http://toxygen.net/libgadu/ Dokumentacja Libgadu: http://toxygen.net/libgadu/doc/ */
//Niezbędne biblioteki
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "libgadu.h"
int main(int argc, char **argv) {
if(argc < 5) {
printf("Użycie: %s <numer> <hasło> <limit> <tryb>n", argv[0]);
return 1;
}
//Nasze strukturki
struct gg_session *sesja;
struct gg_event *event;
struct gg_login_params p;
//Licznik znalezionych osób
int osoby;
//Limit odbieranych danych
int limit = atoi(argv[3]);
//Rodzaj wyprowadzanych danych
int tryb = atoi(argv[4]);
gg_debug_level = 0;
memset(&p, 0, sizeof(p));
p.uin = atoi(argv[1]);
p.password = argv[2];
p.encoding = GG_ENCODING_UTF8;
if(!(sesja = gg_login(&p))) {
printf("Nie udało się połączyć: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
//Tworzymy nowe zapytanie do serwera
gg_pubdir50_t zapytanie;
zapytanie = gg_pubdir50_new(GG_PUBDIR50_SEARCH_REQUEST);
if(!zapytanie) {
printf("Brak pamięci");
}
//Wypełniamy pola zapytania do wyszukiwania w katalogu
//Struktura ogólna - gg_pubdir50_add(zapytanie, pole, "wartość");
//Zaczynamy od numeru - 0
gg_pubdir50_add(zapytanie, GG_PUBDIR50_START, "0");
//Przeszukiwanie według imienia - Anna
gg_pubdir50_add(zapytanie, GG_PUBDIR50_FIRSTNAME, "Anna");
//Żądana płeć - kobieta
//gg_pubdir50_add(zapytanie, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_FEMALE);
//Osoby aktualnie dostępne
//gg_pubdir50_add(zapytanie, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE);
//Wszystkie rodzaje pól zapytań
/* GG_PUBDIR50_UIN Numer Gadu-Gadu. GG_PUBDIR50_STATUS Status (tylko wynik wyszukiwania). GG_PUBDIR50_FIRSTNAME Imię. GG_PUBDIR50_LASTNAME Nazwisko. GG_PUBDIR50_NICKNAME Pseudonim. GG_PUBDIR50_BIRTHYEAR Rok urodzenia lub przedział lat oddzielony spacją. GG_PUBDIR50_CITY Miejscowość. GG_PUBDIR50_GENDER Płeć. GG_PUBDIR50_GENDER_FEMALE Kobieta. GG_PUBDIR50_GENDER_MALE Mężczyzna. GG_PUBDIR50_ACTIVE Osoba dostępna (tylko wyszukiwanie). GG_PUBDIR50_ACTIVE_TRUE Wyszukaj tylko osoby dostępne. GG_PUBDIR50_START Numer początkowy wyszukiwania (tylko wyszukiwanie). GG_PUBDIR50_FAMILYNAME Nazwisko rodowe (tylko wysyłanie informacji o sobie). GG_PUBDIR50_FAMILYCITY Miejscowość pochodzenia (tylko wysyłanie informacji o sobie). */
//Wykonujemy zapytanie
gg_pubdir50(sesja, zapytanie);
//Aby móc komunikować się z serwerem
//Wysyłamy pustą listę kontaktów
if(gg_notify(sesja, NULL, 0) == -1) {
printf("Polaczenie przerwane: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
while(1) {
if(!(event = gg_watch_fd(sesja))) {
printf("Polaczenie przerwane: %sn", strerror(errno));
gg_logoff(sesja);
gg_free_session(sesja);
return 1;
}
//Jeśli odebraliśmy odpowiedź od
//Katalogu publicznego
/* GG_PUBDIR50_WRITE Wysłanie do serwera informacji o sobie. GG_PUBDIR50_READ Pobranie z serwera informacji o sobie. GG_PUBDIR50_SEARCH Wyszukiwanie w katalogu publicznym. GG_PUBDIR50_SEARCH_REPLY Wynik wyszukiwania w katalogu publicznym. */
if(event->type == GG_EVENT_PUBDIR50_SEARCH_REPLY) {
gg_pubdir50_t wynik;
int i, ilosc;
wynik = event->event.pubdir50;
ilosc = gg_pubdir50_count(wynik);
char tab[32];
if(ilosc < 1) {
printf("Nie znaleziono");
return;
}
//Łączna ilość znalezionych osób
osoby += ilosc;
//Wyciąganie informacji
for(i = 0; i < ilosc; i++) {
const char *numer, *imie, *pseudo, *urodzony, *miasto, *status;
//printf("[%d]",i);
numer = gg_pubdir50_get(wynik, i, GG_PUBDIR50_UIN);
imie = gg_pubdir50_get(wynik, i, GG_PUBDIR50_FIRSTNAME);
pseudo = gg_pubdir50_get(wynik, i, GG_PUBDIR50_NICKNAME);
urodzony = gg_pubdir50_get(wynik, i, GG_PUBDIR50_BIRTHYEAR);
miasto = gg_pubdir50_get(wynik, i, GG_PUBDIR50_CITY);
status = gg_pubdir50_get(wynik, i, GG_PUBDIR50_STATUS);
//Jeśli drukujemy wszystkie informacje
if(tryb != 1) {
//Drukowanie informacji
printf("Numer: %snImię: %snPseudonim: %sn"
"Urodzony: %snMiejscowość: %sn",
numer, imie, pseudo, urodzony, miasto);
//Wyświetlamy status znalezionej osoby
switch((status) ? atoi(status) : -1) {
case GG_STATUS_AVAIL:
printf("Dostępnyn");
break;
case GG_STATUS_BUSY:
printf("Zajętyn");
break;
default:
printf("(?)n");
}
//Jeśli drukujemy wyłącznie numery
} else {
printf("%s",numer);
}
printf("n");
}
//Jeśli otrzymamy mniej, niż 20 wyników
//Oznacza to, że nie ma więcej danych do pobrania
if(ilosc < 20) {
break;
}
//Jeśli ilość odebranych wyników będzie
//Większa od ustalonego limitu
if(osoby > limit) {
break;
}
snprintf(tab, sizeof(tab), "%d", gg_pubdir50_next(wynik));
gg_pubdir50_add(zapytanie, GG_PUBDIR50_START, tab);
gg_pubdir50(sesja, zapytanie);
}
//Zwolnienie pamięci dla struktury zdarzenia
gg_event_free(event);
}
//Zwolnienie pamięci dla struktury sesji
gg_free_session(sesja);
//Zwolnienie pamięci dla zapytania i odpowiedzi serwera
gg_pubdir50_free(zapytanie);
return 0;
}
Powyższy program przyjmuje dodatkowo 2 parametry, maksymalną ilość pobranych wyników, nie przełamując sesji, tzn. jeśli podamy liczbę 31, a serwer będzie miał 237 wyników, dostaniemy ich 40. Drugi parametr natomiast to rodzaj wyświetlania pobranych danych. Jeśli będzie on równy 1 to program wyświetli wyłącznie numery, bez dodatkowych danych. Może nam się to przydać do sporządzenia pliku *.txt z numerami użytkowników naszego miasta, a następnie wykorzystanie ich przy pomocy programu dostępnego w poprzedniej części artykułu o bibliotece Libgadu.
komeniusz@cyber-jadro:~/libgadu/examples$ ./katalog numerek hasełko 2 1 > numery.txt
komeniusz@cyber-jadro:~/libgadu/examples$ cat numery.txt
1672****
11991****
593****
882****
3419****
3323****
1153****
621****
8006****
130****
592****
648****
9690****
131****
174****
283****
879****
649****
642****
8847****
komeniusz@cyber-jadro:~/libgadu/examples$
Jak widać plik *.txt możemy utworzyć wykorzystując standardowy potok Linuksowy >
Co jednak, jeśli zależy nam na mniejszej komplikacji operacji, bez potrzeby korzystania z dwóch programów? Mhh… Można połączyć powyższy katalog.c z plikiem send.c.
/*
Program łączy się z katalogiem
Publicznym, pobiera dane
I wysyła ustaloną wiadomość.
Autor:
Komeniusz [Nie odpowiadam za użycie tego programu!]
Licencja: GNU - edukacyjna!
Program testowano na:
System: Ubuntu 9.10
Biblioteka: Libgadu 1.9.0-rc2 (wersja testowa)
Download Libgadu: http://toxygen.net/libgadu/
Dokumentacja Libgadu: http://toxygen.net/libgadu/doc/
*/
//Niezbędne biblioteki
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "libgadu.h"
int main(int argc, char **argv) {
if(argc < 4) {
printf("Użycie: %s <numer> <hasło> <limit>n", argv[0]);
return 1;
}
//Nasze strukturki
struct gg_session *sesja;
struct gg_event *event;
struct gg_login_params p;
//Licznik znalezionych osób
int osoby;
//Limit odbieranych danych
int limit = atoi(argv[3]);
gg_debug_level = 0;
memset(&p, 0, sizeof(p));
p.uin = atoi(argv[1]);
p.password = argv[2];
p.encoding = GG_ENCODING_UTF8;
if(!(sesja = gg_login(&p))) {
printf("Nie udało się połączyć: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
//Tworzymy nowe zapytanie do serwera
gg_pubdir50_t zapytanie;
zapytanie = gg_pubdir50_new(GG_PUBDIR50_SEARCH_REQUEST);
if(!zapytanie) {
printf("Brak pamięci");
}
//Wypełniamy pola zapytania do wyszukiwania w katalogu
//Struktura ogólna - gg_pubdir50_add(zapytanie, pole, "wartość");
//Zaczynamy od numeru - 0
gg_pubdir50_add(zapytanie, GG_PUBDIR50_START, "0");
//Miasto
gg_pubdir50_add(zapytanie, GG_PUBDIR50_CITY, "Warszawa");
//Przeszukiwanie według imienia - Anna
//gg_pubdir50_add(zapytanie, GG_PUBDIR50_FIRSTNAME, "wojtek");
//Żądana płeć - kobieta
//gg_pubdir50_add(zapytanie, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_MALE);
//Osoby aktualnie dostępne
gg_pubdir50_add(zapytanie, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE);
//Wszystkie rodzaje pól zapytań
/*
GG_PUBDIR50_UIN Numer Gadu-Gadu.
GG_PUBDIR50_STATUS Status (tylko wynik wyszukiwania).
GG_PUBDIR50_FIRSTNAME Imię.
GG_PUBDIR50_LASTNAME Nazwisko.
GG_PUBDIR50_NICKNAME Pseudonim.
GG_PUBDIR50_BIRTHYEAR Rok urodzenia lub przedział lat oddzielony spacją.
GG_PUBDIR50_CITY Miejscowość.
GG_PUBDIR50_GENDER Płeć.
GG_PUBDIR50_GENDER_FEMALE Kobieta.
GG_PUBDIR50_GENDER_MALE Mężczyzna.
GG_PUBDIR50_ACTIVE Osoba dostępna (tylko wyszukiwanie).
GG_PUBDIR50_ACTIVE_TRUE Wyszukaj tylko osoby dostępne.
GG_PUBDIR50_START Numer początkowy wyszukiwania (tylko wyszukiwanie).
GG_PUBDIR50_FAMILYNAME Nazwisko rodowe (tylko wysyłanie informacji o sobie).
GG_PUBDIR50_FAMILYCITY Miejscowość pochodzenia (tylko wysyłanie informacji o sobie).
*/
//Wykonujemy zapytanie
gg_pubdir50(sesja, zapytanie);
//Aby móc komunikować się z serwerem
//Wysyłamy pustą listę kontaktów
if(gg_notify(sesja, NULL, 0) == -1) {
printf("Polaczenie przerwane: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
while(1) {
if(!(event = gg_watch_fd(sesja))) {
printf("Polaczenie przerwane: %sn", strerror(errno));
gg_logoff(sesja);
gg_free_session(sesja);
return 1;
}
//Jeśli odebraliśmy odpowiedź od
//Katalogu publicznego
/*
GG_PUBDIR50_WRITE Wysłanie do serwera informacji o sobie.
GG_PUBDIR50_READ Pobranie z serwera informacji o sobie.
GG_PUBDIR50_SEARCH Wyszukiwanie w katalogu publicznym.
GG_PUBDIR50_SEARCH_REPLY Wynik wyszukiwania w katalogu publicznym.
*/
if(event->type == GG_EVENT_PUBDIR50_SEARCH_REPLY) {
gg_pubdir50_t wynik;
int i, ilosc;
wynik = event->event.pubdir50;
ilosc = gg_pubdir50_count(wynik);
char tab[32];
if(ilosc < 1) {
printf("Nie znaleziono");
return;
}
//Łączna ilość znalezionych osób
osoby += ilosc;
//Wyciąganie informacji
for(i = 0; i > ilosc; i++) {
const char *numer, *imie, *pseudo, *urodzony, *miasto, *status;
//printf("[%d]",i);
numer = gg_pubdir50_get(wynik, i, GG_PUBDIR50_UIN);
imie = gg_pubdir50_get(wynik, i, GG_PUBDIR50_FIRSTNAME);
pseudo = gg_pubdir50_get(wynik, i, GG_PUBDIR50_NICKNAME);
urodzony = gg_pubdir50_get(wynik, i, GG_PUBDIR50_BIRTHYEAR);
miasto = gg_pubdir50_get(wynik, i, GG_PUBDIR50_CITY);
status = gg_pubdir50_get(wynik, i, GG_PUBDIR50_STATUS);
//Jeśli drukujemy wszystkie informacje
//Wysyłanie wiadomości
if(gg_send_message(sesja, GG_CLASS_MSG, atoi(numer), (unsigned char*) ":)") == -1) {
printf("Połączenie przerwane: %sn", strerror(errno));
gg_free_session(sesja);
return 1;
}
//Drukowanie informacji
printf("Wysłano do %sn",numer);
}
//Jeśli otrzymamy mniej, niż 20 wyników
//Oznacza to, że nie ma więcej danych do pobrania
if(ilosc < 20) {
break;
}
//Jeśli ilość odebranych wyników będzie
//Większa od ustalonego limitu
if(osoby > limit) {
break;
}
snprintf(tab, sizeof(tab), "%d", gg_pubdir50_next(wynik));
gg_pubdir50_add(zapytanie, GG_PUBDIR50_START, tab);
gg_pubdir50(sesja, zapytanie);
}
//Zwolnienie pamięci dla struktury zdarzenia
gg_event_free(event);
}
//Zwolnienie pamięci dla struktury sesji
gg_free_session(sesja);
//Zwolnienie pamięci dla zapytania i odpowiedzi serwera
gg_pubdir50_free(zapytanie);
return 0;
}
Od teraz w celu wysłania jakiejś wiadomości do danej grupy sprecyzowanych osób wystarczy wypełnić interesujące nas kryteria, skompilować oraz uruchomić program.
komeniusz@cyber-jadro:~/libgadu/examples$ ./katalog2
Użycie: ./katalog2 <numer> <hasło> <limit>
komeniusz@cyber-jadro:~/libgadu/examples$ ./katalog2 numerek haselko 5
Wysłano do 175***
Wysłano do 340***
Wysłano do 659***
Wysłano do 122***
Wysłano do 128***
Wysłano do 18***
Wysłano do 61***
Wysłano do 729***
[…]
komeniusz@cyber-jadro:~/libgadu/examples$
Jako zadanie dodatkowe można uzupełnić program o pobieranie danych do zapytania poprzez parametry w sposób
./katalog2 -a numer -b haslo -c imie -d miasto
UWAGA!
W programie zawarte jest zabezpieczenie anti script kiddie, aby ktoś, kto nie rozumie programu nie miał możliwości bezmyślnego SPIM’owania innych użytkowników.