pax_global_header00006660000000000000000000000064117441033700014512gustar00rootroot0000000000000052 comment=4daef53cfca1324c885ed5dff121ca828ce03789 ekg-1.9~pre+r2855/000077500000000000000000000000001174410337000136175ustar00rootroot00000000000000ekg-1.9~pre+r2855/.cvsignore000066400000000000000000000002311174410337000156130ustar00rootroot00000000000000Makefile config.h config.h.in config.log config.status config.cache configure .DS_Store unoff stdint.h autom4te.cache aclocal.m4 .enable* .with* *.patch ekg-1.9~pre+r2855/ChangeLog000066400000000000000000001277501174410337000154050ustar00rootroot00000000000000Teksty w nawiasach na końcu linii mówią o tym, kto dokonał poprawki. Jeśli jest postaci ,,nick'', powinno być jasne. Postać ,,nick/x'' oznacza, że ,,nick'' jest pomysłodawcą lub podesłał patcha, a zrobił to ktoś oznaczony przez ,,x'' (w - wojtekka, s - speedy, a - arekm, d - drg, sz - szalik, del - deletek, g - gophi, p - porridge). // 2011-06-29 - dodanie fi9o.theme (fi9o/g) // 2011-03-14 - czyszczenie kodu: usunięcie odwołań do gg_base64_encode(), gg_base64_decode() i gg_get_line() (gophi) // 2011-03-07 - typ ignorowania ,,display'' (socek/g) // 2010-03-02 - specjalne traktowanie aliasu /autorun (joshua/g) // 2010-02-02 - wyświetlanie dnd i ffc na liście kontaktów (Kosma/g) - poprawka kolorów dnd i ffc na liście kontaktów (Kosma/g) - aktualizacja FAQ (Kosma/g) // 2009-08-15 - poprawienie konwersji cp na iso (Kosma/g) // 2009-06-26 - aktualizacja manów (gophi) - dodanie /list -f oraz -D (zigi/g) - wypisywanie wyjątków z pythona (korgulec/g) // 2009-06-17 - poprawienie opcji -F i -d (outi/g) // 2009-06-14 - dopisanie krótkiej informacji o otrzymywaniu dnd i ffc do faq (gophi) // 2009-06-11 - wyrzucenie starej poprawki - nowy klient nie wysyła tego po zalogowaniu, wszystko działa dobrze (darkjames/g) // 2009-06-05 - poprawki w gtk (darkjames/g) - włączenie informowania o statusach z gg 8.0 (darkjames/g) - male poprawki w ffc/dnd (gophi) - wymaskowanie (nieznanej) flagi 0x4000 ze statusu dla protocol 0x2E (darkjames/g) // 2009-05-29 - poprawienie buga z pobieraniem userlisty (Dominik Biały/g) - nowe opisy z libgadu: poGGadaj ze mną i nie przeszkadzać (gophi) // 2009-04-17 - dodanie dwóch buildów nowego gg (nie jestem pewien czy powinno nazywać się "nowe gadu-gadu", ale skoro gg samo tak nazywa ten produkt to chyba tak...) (darkjames/g) // 2008-12-16 - poprawki w dokumentacji (zigi/g) // 2008-12-07 - poprawienie obsługi eventów disconnected i connectionlost (gophi) // 2008-09-09 - poprawienie poprawki (gophi) // 2008-09-08 - poprawienie alt-a przy różnych typach aktywności okienek (gophi) - poprawienie changeloga (Kosma/g) // 2008-07-23 - konwersje iso/utf w gtk (darkjames/g) // 2008-07-06 - długo oczekiwane rozróżnianie typu aktywności w okienku (darkjames/g) // 2008-05-18 - dodanie komunikatu o zamianie okien miejscami (Marcin Rybak/g) // 2008-05-18 - dodanie /window swap (gamster,Marcin Rybak/g) // 2008-05-17 - dopisanie do FAQ informacji na temat UTF-8 (demreath/g) - inne drobne aktualizacje FAQ (gophi) - kolejne informacje o UTF-8 (Kosma,porridge/g) // 2008-05-15 - aktualizacja TODO (gophi) // 2008-05-13 - dodanie docs/protocol.html zawierającego jedynie odnośnik do strony libgadu; usunięcie tego pliku spowodowało brzydkie 404 na stronie WWW ekg (darkjames/p) // 2008-04-21 - aktualizacja odsyłacza do informacji o instalacji aspella (zigi/p) - drobna poprawka dokumentacji /list -I (zigi/p) // 2008-04-19 - porządki w dokumentacji w związku z wydzieleniem libgadu (p) - usunięcie z configure bezużytecznej informacji o pthread (p) - poprawienie deklaracji powłoki w skryptach wymagających basha (p) // 2008-03-24 - aktualizacja dokumentacji (gophi) // 2008-02-06 - aktualizacja dokumentacji i wersji (cvs -> svn) (zigi/g) // 2008-02-02 - poprawienie błędu kompilacji (zigi/g) // 2008-01-27 - niech nie robi lseek(-1, 0, SEEK_END); (darkjames/g) - kolorki w debug, skopiowane z ekg2 i pluginu gg :) (zamiast stalych z libgadu sa uzyte numeryczne, zeby nie bylo bledow kompilacji w przypadku niezgodnosci wersji libgadu z oczekiwana) (darkjames/g) - jesli ekg nie ma obslugi voipa, to jak dostaje rozmowe glosowa, niech robi wczesniej gg_dcc7_reject() (darkjames/g) // 2008-01-26 - gtk: poprawka nazwy kontaktu (darkjames/g) - gtk: jak mamy debug, to logujmy do okienka (darkjames/g) - gtk: poprawka z xchata (darkjames/g) - gtk: cleanup strukturki i tworzenia okienka gtkowego (darkjames/g) // 2007-12-24 - gtk: RMB na userze pokazuje więcej informacji (grupy, ip, ostatnio widziano, ostatnie ip) (darkjames/g) - gtk: więcej opcji w menu (wiekszość jeszcze nie działa) (darkjames/g) - gtk: s/TAG_IRC/TAG_WINDOW/g (darkjames/g) - gtk: pixmaps_init(): zmienne na początek bloku (darkjames/g) - gtk: poprawka w command_exec_format() (darkjames/g) // 2007-12-01 - gtk: kolejne zmiany, wydzielenie ikonek z powodów licencyjnych (darkjames/g) - gtk: poprawka w pixmaps_init (gophi) // 2007-11-25 - gtk: poprawki warningów (darkjames/g) - gtk: reagowanie na event "userlist_changed" (darkjames/g) - gtk: reagowanie na komendę /query (skopiowane z ncurses) (darkjames/g) - gtk: dodanie kilku rzeczy do menu (darkjames/g) - gtk: można dodawać kolory przy pisaniu (darkjames/g) - gtk: cleanup, zmiana stylu kodowania (darkjames/g) - gtk: o programie (darkjames/g) - gtk: informacje o uzytkowniku prawoklikniętym na userliście (darkjames/g) - gtk: dwuklik na użytkowniku robi na nim /query (darkjames/g) // 2007-11-22 - kilka zmian w gtk (darkjames/g) // 2007-11-21 - dodanie eksperymentalnego ui GTK (tak, ekg na iksach!). kawał dobrej roboty darkjamesa :) (darkjames/g) // 2007-11-04 - naprawienie błędu kompilacji (backtrace) na niektórych FreeBSD (gophi) // 2007-08-15 - dopisanie linku do rejestracji numerka przez www (gophi) // 2007-07-22 - gophi.theme :) (gophi) // 2007-07-07 - dopisanie do docs/libgadu.txt instrukcji dla libgadu instalowanego lokalnie (zigi/g) - dodanie zmiennych files_mode_config, files_mode_received (Socek/g) // 2007-07-05 - wydzielenie libgadu. kiedyś trzeba było to zrobić... (gophi) - dcc7 (wojtekka/g) // 2007-06-13 - poprawienie zamykania deskryptorów (darkjames/g) - poprawienie bindowania Ctrl-costam (qyon,darkjames/g) // 2007-05-08 - dostosowanie /find do 8-cyfrowych numerów (gophi) // 2007-04-27 - libgadu: poprawienie obcinania \r w gg_get_line() (darkjames/g) - dodanie zmiennej userlist_backup (kanedaaa/g) // 2007-04-21 - libgadu: poprawienie wycieku deskryptorów w resolverze opartym na wątkach (w/g) - libgadu: poprawienie możliwości nieprawidłowego zachowania resolvera opartego na procesach (w/g) - libgadu: race condition w resolverze opartym na procesy (w/g) // 2007-04-18 - gg 7.7 build 3315 (darkjames/g) // 2007-04-04 - signedness w ioctld.c (gophi) // 2007-03-29 - aktualizacja dokumentacji (gophi) // 2007-03-24 - dodanie pliku addons.txt (gophi) // 2007-03-21 - konwersja tabulacji na spację podczas odbierania wiadomości (Rodion/g) - optymalizacja funkcji konwertujących zestawy znaków (gophi) - poprawienie pokazywania czasu kompilacji (adwol/g) // 2007-03-10 - poprawienie bezpieczeństwa przy okazji tokenów (w/g) - poprawienie stylu (gophi) // 2007-03-05 - poprawka wycieku pamięci w przypadku niepowodzenia zapisu listy kontaktów (darkjames/p) // 2007-02-22 - dostosowanie skryptu vekg do nowych wersji valgrinda (w) - poprawka off-by-one przy obsłudze tokenów (w) - poprawka wycieku pamięci przy brakujących polach listy kontaktów (w) - poprawka potencjalnego wycieku pamięci przy zmianie hasła (darkjames/w) // 2007-02-18 - napisanie i dodanie listmerge.c do contrib/ (s_wilk/g) // 2007-02-13 - dodanie /set encryption 2 i 3 (chomzee/g) // 2007-01-28 - libgadu: common.c: gg_get_line(): drobna optymalizacja; gg_connect: dodane zamykanie gniazda po niepowodzeniu w bind() (mslusarz/p) - dodany skrót mojego nicka w changelogu (porridge) // 2007-01-24 - configfile.c:333: warning: 'str' may be used uninitialized in this function (gophi) - signedness w voice.c (gophi) // 2007-01-11 - błąd w userlist_write_wap() (demreath/g) // 2007-01-07 - literówka w api.txt (witać -> widać) (zigi/g) // 2007-01-07 - uin/alias -> numer/alias w /help (przy unregister) (g) // 2006-12-27 - memleak w cmd_set (darkjames/g) // 2006-12-21 - literówka w protokole (gophi) // 2006-11-30 - eskejpowanie niebezpiecznych znaków na userliście (sawik/g) - wyodrębnienie kodu eskejpującego i dekodującego konfigurację do dynstuff (gophi) // 2006-11-29 - usunięcie wycieku pamięci w events.c:handle_dcc:GG_EVENT_DCC_ERROR (darkjames/p) // 2006-11-27 - a gdyby tak ekg umiało zrzucać stos wywołań po segfaulcie? :) (gophi) // 2006-11-18 - dodanie zmiennej msg_as_chat (gophi) // 2006-11-14 - sms-express Sp. z o.o. -> Gadu-Gadu S.A. (gophi) - segfault przy /list -r (zigi/g) - 7.6 build 1688 (neeo/g) // 2006-11-10 - regexpy w poleceniu /list (met/g) // 2006-11-06 - 7.6 build 1359 (incuś/g) // 2006-10-23 - zamiana realloków na string_t (darkjames/g) // 2006-10-22 - dodanie polecenia /for (gophi) - kilka kosmetycznych zmian w commands.c (gophi) // 2006-10-20 - wyciek pamięci przy okazji obrazków (gophi) // 2006-10-19 - ignore msg działa też dla obrazków (gophi) // 2006-10-16 - zapisywanie wielolinijkowych zdarzeń, opisów etc. (gophi) // 2006-10-15 - poprawienie błędu przy ekg_getch() (darkjames/g) // 2006-10-01 - dopisanie wersji klienta 7.5.0 (build 2201) (gophi) // 2006-09-26 - więcej powiadomień o stanie doręczenia wiadomości (gophi) // 2006-09-23 - drobna poprawka w sim.txt (zigi/g) // 2006-09-22 - poprawiony wyciek pamięci w dwu generatorach (darkjames/p) // 2006-09-08 - dodanie zdarzenia image dla obrazków (struthio/g) - zaktualizowanie tohver.theme (Efrum/g) // 2006-08-29 - poprawiony wyciek pamięci przy parsowaniu config_server (darkjames/p) // 2006-08-27 - dodanie fsync() i sprawdzanie close() przy zapisywaniu obrazka (porridge) // 2006-08-11 - stan wykonania poleceń powłoki wywoływanych przez mysz niekoniecznie musi być wyświetlany ;) (outsiderek/g) // 2006-08-09 - poprawienie literówek w dokumentacji (embe) // 2006-08-07 - poprawki obsługi błędów skryptów Pythona (embe) - poprawka konwersji pliterek w ścieżkach do obrazków (embe) - poprawienie użycia window_current po free() (embe) // 2006-08-05 - wyodrębnienie dcc_backups i zastosowanie do obrazków (gophi) - dodanie wywoływania zdarzenia dccfinish do obrazków (gophi) - dopisanie buga związanego z dcc_backups do TODO (gophi) // 2006-08-03 - poprawienie zapisywania obrazkow (eMBe/g) - poprawienie signed/unsigned (a przez to psucia polskich znaków) związanego z dcc i obrazkami (eMBe/g) - wyodrębnienie fix_filename() (gophi) - dodanie zmiennej image_size (Kosma/g) - przystosowanie Makefile.in do autoconfa 2.60 (eMBe/g) - poprawienie warningów signed/unsigned na gcc 4.0.3: commands.c, stuff.c (gophi) // 2006-08-02 - zapisywanie obrazków (Socek,Kosma/g) - dopisanie do FAQ kilku punktów (nvm/g) // 2006-07-29 - poprawienie buga /query numerek; /chat $ wiadomość (eMBe/g) - gesty myszy (gophi) - poprawienie kilku warningów na gcc 4.0.3 (gophi) // 2006-07-23 - poprawienie wyświetlania kolorów (Kosma,eMBe/g) // 2006-07-16 - dodanie maski nomsg do /set make_window (Kosma/g) // 2006-07-14 - dodanie obsługi statusbara do obsługi myszy (gophi) // 2006-07-12 - dodanie obslugi myszy (gophi) // 2006-06-30 - libgadu: poprawienie kompilacji na gcc 4.1 (AstralStorm/g) - libgadu: cofnięcie poprzedniego commita (więcej psuje niż naprawia) (w/g) // 2006-06-10 - poprawka struct fstring_s.ts z int na time_t (porridge) - aktualizacja adresu strony (gophi) // 2006-05-18 - libgadu: poprawienie paru wycieków pamięci (gj/g) // 2006-05-17 - naprawienie /status w readline (gophi) // 2006-05-16 - aktualizacja protokołu (Cinu/g) // 2006-05-09 - nowy format odpowiedzi na rejestrację (ksadlocha/g) - informacja o zmianie daty w oknie (mj/g) // 2006-04-13 - libgadu: poprawienie buga sprawiającego, że czasami zostają zombie po resolverze (czes,kosma/g) // 2006-04-11 - zmiana algorytmu przyporządkowywania znaków pikselom w tokenach, parę drobnych zmian w obsłudze tokenów (gophi) - update /help set display_token (gophi) // 2006-04-10 - poprawienie kompilacji z libungif bez libjpeg (zigi/g) // 2006-04-09 - dodanie eksperymentalnego wyświetlania gifowych tokenów (gophi) - dodanie /set nick (petros,jceel/g) - aktualizacja FAQ i /help token (gophi) // 2006-04-06 - libgadu: dopisanie zamykania rodzicielskiej strony rurki w procesie potomnym resolvera w wersji bez pthreads (gophi) // 2006-03-28 - libgadu: dodanie GG_FAILURE_UNAVAILABLE, podbicie API (gophi) // 2006-03-27 - drobna poprawka językowa w /help /on (gophi) // 2006-03-26 - zaktualizowanie listy rzeczy do zrobienia (gophi) - libgadu: dodanie GG_FAILURE_INTRUDER, podbicie API (gophi) // 2006-03-19 - możliwość pobierania listy okien w skryptach pythonowych (kajoj/w) // 2006-02-18 - poprawka kompilacji na DragonFly (arachnist/w) // 2006-02-15 - dodanie opcji umożliwiającej wyłączenie openssl tylko w libgadu (porridge) // 2006-02-07 - lepsze zgłaszanie błędów libjpeg, zamiast mechanizmu domyślnego: fprintf(stderr,...); exit() (porridge) // 2006-02-03 - poprawka kompilacji gcc 4: deklaracja ioctld_socket() (porridge) // 2006-01-29 - poprawka /help set beep (zigi/g) // 2005-12-06 - poprawka literówki sprawiającej, że komenda /play nie działa (sz) // 2005-12-05 - libgadu: dodanie atrybutu ,,static'' do funkcji, które nie są wykorzystywane poza swoimi modułami (Richard Laager/w) - poprawki deklaracji funkcji (Richard Laager/w) // 2005-12-03 - odpowiedni komunikat dla polecenia sms, play oraz say, gdy nie ustawiono właściwej zmiennej (zigi/sz) // 2005-11-26 - dodanie opcji slash_messages (gophi) // 2005-11-20 - poprawka ostatnich zmian związanych z odróżnianiem komend od zwykłego tesktu; "/back http://foo.com" w oknie wiadomości jest traktowane jako komenda (weirdo/sz) // 2005-11-19 - dopisanie wersji klienta 7.0 (build 22 lub nowszy) (jceel/g) // 2005-11-16 - traktowanie wpisania w czasie rozmowy np. ,,/bin/ls'' jako wiadomości, a nie komendy. wzorowane na interfejsie irsii (weirdo/sz) // 2005-11-14 - poprawka obsługi błędów przy zapisie zawartości okna (porridge/w) // 2005-11-13 - poprawienie paru literówek w /help (gophi) // 2005-11-12 - drobna poprawka w manualu (gophi) // 2005-11-10 - dodanie /window dump (jaro3000/w) // 2005-11-02 - umożliwienie kompilacji na GNU/kFreeBSD (aurel32/p) // 2005-10-29 - usunięcie zmiennej era_omnix (w) // 2005-10-21 - dodanie wersji klienta 7.0 (build 1 lub nowszy) (gophi) // 2005-10-12 - dodanie polecenia /window oldest i skrótu klawiaturowego Alt-S, umożliwiającego płynniejsze prowadzenie rozmowy z kilkoma osobami jednocześnie, niż /window active (Alt-A) (gophi) // 2005-10-09 - poprawka działania wykrywania niewidocznych - gdy wyślemy zapytanie sprawdzające do osoby, która jest niedostępna i rozłączymy się, a w międzyczasie klient tej osoby odbierze pakiet oraz odpowie na niego, to po naszym powrocie nie dostaniemy błędnej, chwilowej informacji o ukrywaniu się tej osoby (sz) // 2005-09-19 - poprawienie kilku błędów typu ,,memory leak'' (sz) // 2005-09-16 - poprawienie literówki w /help set ioctl_enable (zigi/g) // 2005-09-15 - poprawienie wykrywania płci podczas niedostępności kontaktu, któremu chcemy wysłać plik (met/g) // 2005-09-10 - rozpoznawanie gg 7.0 w /list i dodanie tej wersji do dokumentacji (sz) - poprawienie małej literówki w /help set check_mail (dude/g) // 2005-09-01 - w pythonie, ekg.command() działa poprawnie w deinit() (irys/sz) // 2005-08-30 - możliwość obsługi dowolnych poleceń w pythonie - handle_command_line() (outsiderek/sz) // 2005-08-29 - zwalnianie pamięci po /set aspell 0 (sz) // 2005-08-28 - kosmetyka związana z obsługą aspell'a (sz) - literówki w dokumentacji protokołu (embe/sz) // 2005-08-12 - dodanie do /dcc pokazywania prędkości i pozostałego czasu transferu pliku (gophi) - zmiany obsługi sygnałów na zgodne z Posix'em, zdarzenia związane z sygnałami SIGUSR nie są wywoływane z kontekstu procedury obsługi sygnału (embe/sz) // 2005-08-03 - dodanie warninga przed inicjowaniem aspella (porridge/g) - poprawka poprzedniego commita (embe/g) - poprawienie wycieku pamięci przy obsłudze aspella (embe/g) - poprawienie wcięć i obsługi błędów przy obsłudze aspella (embe/g) // 2005-07-29 - niezależnie od konfiguracji, ekg wewnętrznie widzi wszystkie możliwe zmienne - dzięki temu eksport/import listy kontaktów wraz z konfiguracją pomiędzy różnymi instalacjami ekg (np. z ioctld i bez) działa poprawnie (sz) // 2005-07-18 - libgadu: poprawna reakcja na pakiet GG_NEED_EMAIL (adwol/w) - dodanie informacji o pakiecie GG_NEED_EMAIL do opisu protokołu (adwol/w) // 2005-07-17 - libgadu: poprawne zdarzenia GG_EVENT_IMAGE_REPLY, gdy klient po drugiej stronie nie ma żądanego obrazka (ono/sz) // 2005-07-16 - libgadu: poprawka dwóch błędów typu integer overflow -- ilość odbiorców wiadomości większa niż 0x3fffffff spowoduje przekroczenie zakresu zmiennych i zaalokowanie zbyt małej ilości pamięci przy obsłudze konferencji (CAN-2005-1852) (mslusarz/w) // 2005-07-13 - poprawka ustawiania tytułu terminala po rejestracji (w) // 2005-07-12 - poprawki bezpieczeństwa i inne pomniejsze contrib/scripts/ekgbot-pre1.py (CAN-2005-1851) (porridge) - poprawki zachowania komend /_image* na maszynach big-endian (CAN-2005-2369) (w) // 2005-07-11 - poprawki bezpieczeństwa skryptów w contrib/ (CAN-2005-1850) (porridge) - poprawki bezpieczeństwa contrib/scripts/linki.py (CAN-2005-1916) (eromang/w) // 2005-07-04 - możliwość wstawienia początkowych spacji w opisie, należy użyć składni /away \ opis ze spacja na poczatku (zigi/sz) - libgadu: poprawki dla maszyn Big Endian (mslusarz/sz) // 2005-06-25 - libgadu: rozpoznawanie GG_HAS_AUDIO_MASK oraz GG_ERA_OMNIX_MASK także w przypadku GG_NOTIFY_REPLY60, a nie tylko GG_STATUS60 (zigi/sz) - libgadu: podbicie wersji API po ostatnich zmianach (sz) - libgadu: bład przy obsłudze GG_NOTIFY_REPLY na Big-Endianach (sz) // 2005-06-24 - uzupełnienie opisu protokołu o połączenia z bramki Era Omnix, uzupełnienie numerków wersji 6.0 i 6.1 oryginalnego klienta (sz) - /list pokazuje, kto łączy się przez bramkę Era Omnix (sz) - uaktualnienie dj.theme (benetnash/sz) // 2005-06-23 - dodanie zmiennej ,,era_omnix'' (*/sz) - libgadu: możliwość udawania klienta era omnix (*/sz) // 2005-06-20 - poziom ignorowania ,,smsaway'' (sz) // 2005-06-19 - libgadu: poprawka wyrównania dostępu do pamięci, która likwiduje SIGBUS na SPARCach (CAN-2005-2370) (embe/w) // 2005-06-07 - poprawienie ustawiania scieżki wyszukiwania modułów pythona na systemach zgodnych z SUSv2 (embe/p) // 2005-06-05 - umożliwienie wpisywania wiadomości zaczynających się od slasha (Kosma/g) // 2005-05-31 - dodanie do windows_save zapisu stanu okien przy /save (Kosma/g) // 2005-05-25 - drobna poprawka /help play (gophi) // 2005-05-22 - poprawka zachowania simlite przy wiadomościach dłuższych niż 628 znaków (mslusarz/w) // 2005-05-14 - po pierwszym wyświetleniu pełnego ostrzeżenia o filtrowaniu wiadomości przez serwer, pozostałe takie będą wyświetlane w skróconej formie do restartu ekg (joshua/p) // 2005-05-13 - poprawienie kodu konferencji (rodion/g) // 2005-05-03 - drobna poprawka indentacji w ./configure (gophi) // 2005-04-29 - poprawienie obsługi zdarzeń konferencji (rodion/g) // 2005-04-28 - wyłączenie sprawdzania błędów w GCC dot. pthreads przy --disable-shared i reorganzacja tegoż sprawdzania w acx_pthread.m4 (porridge) // 2005-04-25 - log_ignored uwzględnia także zmiany stanu (kosma/g) - poprawienie literówki w /help on (jceel/g) // 2005-04-21 - poprawki wykrywania pthread na amd64 i FreeBSD 4.1x (porridge) - wycofanie zmiany wykrywania niewidocznych - wiecej problemów niż pożytku (sz) // 2005-04-20 - zmiana techniki wykrywania niewidocznych (del/sz) // 2005-04-12 - dodanie zmiennej dcc_backups (KKKas/g) - libgadu: pozbycie się warningów przy -O2 (porridge/sz) - nie dodajemy siebie do konferencji, ani wielokrotnie tych samych osób (mslusarz/sz) // 2005-04-09 - poprawienie literówki w obsłudze konferencji (petros/g) - ,,beep_notify'' też bierze pod uwagę zmienną ,,events_delay'' (sz) // 2005-03-24 - libgadu: poprawki związane ze znakami zmiennych (gj/w) // 2005-03-19 - libgadu: poprawki zwracanych wartości w errno w przypadku błędu (mslusarz/sz) - kompilacja na AMD64 i GCC 4.0 (Andreas J/sz) // 2005-03-17 - drobne poprawki w /help (*/sz) // 2005-03-09 - /check_conn @grupa (zigi/sz) // 2005-03-02 - usuwanie wpisu, np. email za pomocą /list user -e "" (sz) // 2005-02-28 - drobna poprawka /help w domyślnym motywie (gophi) // 2005-02-27 - drobne kosmetyczne poprawki, głównie kompilacji z pythonem (sz) // 2005-02-26 - dodanie zmiennej status_window (shog/g) // 2005-02-24 - wyświetlanie niedostępności po połączeniu dla członków grupy ,,spied'' zgodne ze zmienną ,,events_delay'' (zigi/sz) // 2005-02-22 - możliwość dodawania niewidocznych do listy dopełnień (zigi/sz) - mniej ,,śmiecące'' wykrywanie niewidocznych (sz) // 2005-02-21 - libgadu: podbicie wersji API (porridge/w) // 2005-02-18 - poprawka /list -m (KKKas/w) - poprawka /check_conn dla osób spoza grupy spied (zigi/sz) - proste przewijanie listy kontaktów, standardowo podbindowane pod Alt-Z oraz Alt-X (sz) - libgadu: poprawka zachowania gg_urlencode() przy pustych tekstach (mslusarz/w) - libgadu: optymalizacja gg_chomp() (mslusarz/w) // 2005-02-17 - libgadu: podbicie API z 3.1 do 3.2 (sz) - libgadu: dodanie gg_remind_passwd3, która dodatkowo pobiera email jako parametr (zigi/sz) - konsekwentne zachowanie przy ,,ignore_empty_msg'' równym 0 i otrzymaniu pustej wiadomości z obrazkiem(ami). wyświetlana jest pusta wiadomość (zigi/sz) - reorganizacja polecenia check_conn, patrz /help_check_conn (zigi/sz) // 2005-02-15 - zdarzenia ,,connectionlost'' oraz ,,disconnected'' (reef/sz) - łatwiejsze wykrywanie niewidocznych, patrz /help check_conn (sz) // 2005-02-01 - poprawienie segfaulta podczas /query z 10 znakowym nickiem ze spacją (mimek,ramzes/g) - poprawienie /set log_status (gophi) - poprawienie /help /set quit_reason (gophi) // 2005-01-30 - dodanie zmiennej ,,ignore_empty_msg'' (porridge/sz) - pomijanie ,,\r\n'' w ostatniej linii np. wielolinijkowego statusu (kosma/sz) - dodanie funkcji check_conn pomagającej sprawdzać czy ktoś jest niewidoczny (*/del) // 2005-01-29 - poprawka segfaultu przy wyświetlaniu tokenów (gj/w) - poprawka ocrowania tokenów (w) - libgadu: parsowanie adresów tokenów, żeby działały z proxy (porridge/w) // 2005-01-26 - poprawienie wyświetlania informacji na temat zakolejkowania wiadomości (teraz wyświetlana jest pod wiadomością) (gophi) - dopisanie do ,,/help on'' informacji na temat podawania sprawcy dla zdarzeń ,,connected'' i ,,disconnected'' (zigi/g) // 2005-01-21 - libgadu: podbicie wersji API z 3.0 do 3.1 (porridge/w) - libgadu: cofnięcie poprawki off-by-one gg_base64_encode() (porridge/w) // 2005-01-19 - dodanie zdarzeń ,,connected'' i ,,disconnected'' (LANO/sz) // 2005-01-12 - dodanie do informacji wypisywanych w momencie segfaulta tekstu na temat możliwości otrzymania core przy pomocy ,,ulimit'' (gophi) - poprawienie poprzedniego commita (z rozpędu źle nałożyłem patcha) (gophi) // 2005-01-11 - dodanie zmiennej beep_title, obsługującej informowanie o sygnale dźwiękowym w pasku tytułowym na terminalu xterm (qbq/w) - libgadu: sprawdzanie poprawności parametrów funkcji gg_send_message_richtext() i gg_send_message_confer_richtext() (mslusarz/w) // 2005-01-10 - poprawienie segfaulta przy próbie dołączenia kogoś do nieistniejącej konferencji (irys/g) // 2005-01-04 - libgadu: poprawka połączenia przez proxy (porridge/w) // 2004-12-28 - libgadu: dodanie funkcji gg_dcc_fill_file_info2() pozwalającej na podanie lokalnej nazwy pliku innej niż przesyłanej zdalnemu klientowi, na przykład gdy lokalne kodowanie jest inne niż CP1250 (mslusarz/w) - libgadu: poprawka zachowania przy wysyłaniu pustych plików (mslusarz/w) - libgadu: poprawka tworzenia krótkiej nazwy przesyłanych plików (w) - nazwy przesyłanych plików są tłumaczone na CP1250 (mslusarz/w) - dodanie zmiennej ,,dcc_filter'' pozwalającej na chwilowe wyłączenie filtrowania nieznanych adresów IP w połączeniach bezpośrednich (w) // 2004-12-21 - libgadu: zamykanie gniazda nasłuchującego dcc w przypadku problemów z bindowanie/słuchaniem (mslusarz/w) - libgadu: uproszczenie gg_send_packet() (mslusarz/w) - libgadu: uzupełnienie stałych potwierdzeń (mslusarz/w) - libgadu: usunięcie kodu ustawiającego gg_dcc_ip na auto w funkcji gg_dcc_socket_create() (mslusarz/w) - uzupełnienie dokumentacji protokołu o połączenia bezpośrednie i nowy format listy kontaktów (w) // 2004-12-19 - uzupełnienie dokumentacji protokołu o tokenu (w) // 2004-12-15 - usunięcie malutkiego wycieku zasobów, jeśli korzystamy z wątkowego resolvera w libgadu (sz) // 2004-12-12 - dodanie pamiętania numerków przy wykrywaniu osób spoza listy (zigi/g) // 2004-12-10 - dodanie wykrywania osób w trybie ,,tylko dla znajomych'', które mają nas na liście kontaktów (gophi) // 2004-12-06 - poprawienie obsługi zdarzeń dotyczących numeru 1 (gophi) - libgadu: poprawienie off-by-one w gg_base64_encode() (thv/w) // 2004-12-01 - poprawienie segfaulta przy /queue -u user (zigi/g) // 2004-11-30 - drobna poprawka w /help unregister (zigi/g) // 2004-11-29 - drobna poprawka w /help set (zigi/g) // 2004-11-28 - jeśli wiadomość zawiera obrazki, ale nie posiada tekstu, jest całkowicie ignorowana - zapobiega śmieceniu przez osoby używające wykrywanie niewidocznych (sz) // 2004-11-27 - dodanie nachodzących na siebie linii przy scrollowaniu (jceel/g) - usunięcie buga przy /help set // mały opis dostępnych zmiennych (gophi) // 2004-11-25 - kilka poprawek w dokumentacji (gophi) - poprawienie debugowania ncurses (gophi) // 2004-11-22 - poprawienie błędu ,,Za mało parametrów. Spróbuj help chat'' podczas uruchamiania z wysłaniem wyniku (-m, -b) niektórych poleceń systemowych, np. ,,/exec -m numerek echo'', ,,/exec -b numerek echo -n'' (g) // 2004-11-19 - poprawienie błędu przy obsłudze zdarzenia zmiany opisu własnego numerka (acze/g) - wyeliminowanie warninga podczas kompilacji stuff.c (g) // 2004-11-17 - poprawienie kolejności logowania podczas wykonywania zdarzeń zawierających akcje msg/chat (g) - poprawienie buga podczas dodawania zdarzeń dotyczących osób spoza listy kontaktów (zamiast numeru osoby był dodawany numer zdarzenia) (g) // 2004-11-11 - usunięcie dziur w numeracji zdarzeń (gophi/w) - poprawka zachowania readline (gophi/w) - dodanie opisu opcji -o (gophi/w) - poprawka odświeżania ekranu podczas używaniu control-pipe (gophi/sz) // 2004-10-31 - usunięcie wycieku pamięci przy korzystaniu z formatów contacts_header* i contacts_footer* (weirdo/w) // 2004-10-29 - poprawka wykrywania pthread (porridge/w) // 2004-10-28 - libgadu: współbieżny resolver tam gdzie jest gethostbyname_r (mslusarz/w) // 2004-10-12 - libgadu: poprawka liczenia sumy kontrolnej obrazków (mslusarz/w) - libgadu: poprawka wysyłania dużych pakietów (mslusarz/w) - nowa zmienna ,,dcc_port'' (adaml/w) // 2004-10-07 - libgadu: poprawka pobierania tokenow (szalik/w) // 2004-10-06 - libgadu: optymalizacja zwalniania zasobów (mslusarz/w) // 2004-10-05 - libgadu: poprawka wycieku pamięci w przypadku braku zasobów (mslusarz/w) // 2004-08-09 - poprawka błędy zawieszenia programu związanego z dopełnieniem (tros/del) // 2004-08-10 - poprawka powiadamiania o nowej poczcie (atler/sz) // 2004-07-14 - libgadu: poprawki obsługi proxy (the_leech/w) - libgadu: poprawka złego zachowania po rozłączeniu klienta (patryk/w) // 2004-07-06 - poprawka działania /queue -u user -c (struthio/sz) // 2004-06-19 - poprawka wycieku pamięci (szalik/del) // 2004-06-13 - poprawka dopełnienia tabem przy tekstach zawierających cudzysłów (KKKas/del) // 2004-06-11 - poprawka informacji o podszywaniu się w dcc (perry/w) - poprawki dokumentacji protokołu (Piotr Trzcionkowski/w) // 2004-05-27 - zaległe uaktualnienie opisu protokołu: dzielenie listy kontaktów na pakiety przy imporcie i eksporcie (w) // 2004-05-22 - poprawiony błąd końca wiersza przy exec --{b}msg (Reef/del) // 2004-05-03 - poprawka małego błędu związanego z alokacją pamięci (h3r0n/del) // 2004-05-02 - libgadu: obsługa list kontaktów większych niż 409 wpisów (MAG,adrians/w) - uaktualnienie dokumentacji protokołu o większe listy kontaktów (w) // 2004-04-28 - informacja o próbie podszycia się pod użytkownika przy połączeniach bezpośrednich (acze/w) // 2004-04-26 - poprawione złe wyświetlanie czasów przy /status w readline (kbns/del) // 2004-04-17 - poprawione tabcompletion (błędy z cudzysłowiami) (MS/del) // 2004-04-06 - poprawka tabcompletion dla nazw plików (Brzezi/del) - poprawka problemu z 'query odbiorca wiadomosc' (Sydney/del) // 2004-04-05 - poprawka błędu z ustawianiem opisu i stanu przy łączeniu (nik/del) // 2004-04-04 - poprawka wycieku pamięci przy /set contacts_size 0 (mirek/del) // 2004-03-28 - poprawka dotycząca tabcompletion (del) // 2004-03-23 - usunięty błąd z dopełnieniem np /dcc g[TAB] (Wojciech S/del) // 2004-03-21 - usunięty błąd przy query mającym utworzyć konferencję, np: /query "Imię Nazwisko",nick wyśle komunikat zamiast tworzyć konferncję (del) - parę poprawek dotyczących wew. funkcji (del) // 2004-03-03 - poprawka TAB completition (pare błędów, cleanup, komentarze) (del) - poprawka sprawdzająca parametry komendy /query (samo /query wyrzuca komunikat o błędzie, a /query @nieistniejaca_grupa nie wyrzuca "krzaczków") (del) - poprawka formatu ,,ncurses_timestamp'' (kfahoo/w) - uaktualnienie arim.theme (arim/w) // 2004-03-02 - poprawka błędów z dopełnieniem klawiszem TAB (min. segv) (del) - działające tab_commmand (del) - dodanie ,,Requires: openssl'' w libgadu.pc w razie potrzeby (krzak/w) // 2004-03-01 - literkówka w vars.txt (porridge/d) // 2004-02-29 - dopełnianie listy nicków abc,def,ghi (joshua/del) - przy dopełnieniu obsługa dużych/małych polskich liter (del) // 2004-02-28 - poprawka obsługi dużych polskich literek w słowniu (del) - dopełnianie w środku linii (sz/del) // 2004-02-27 - zastąpienie zmiennej aspell_allowed wewnętrzną funkcją sprawdzającą (del) - wyczyszczony kod i dodana obsługa adresów WWW i FTP (nie są podkreślane) w słowniku (del) // 2004-02-26 - zapomniany contrib/ioctld-client.c - dodanie zmiennych ioctld_enable oraz ioctld_net_port, które umożliwiają zdalne działanie daemona ioctld (d) - dodanie zmiennej local_ip, pozwalajającej na ustawienie adresu lokalnego (del) - dodanie dokumentacji słownika aspell (del) - poprawka teoretycznej możliwości segfaulta w module aspell'a (del) - poprawka w module aspell'a dotycząca sprawdzania pisowni przy zawijanych wierszach (del) - dodanie zmiennej aspell_allowed określającej jakie znaki mają być ignorowane (np. nawiasy czy cudzysłowia) (del) // 2004-02-25 - sprawdzanie pisowni (deli/w) // 2004-02-16 - poprawka zakończenia linii w wielolinijkowych wiadomościach z potoku sterującego (reef/w) // 2004-02-14 - dodanie pythonowych zdarzeń handle_status_own i handle_msg_own do poprawiania własnych stanów i wiadomości (*/w) // 2004-02-13 - pomijanie ignorowanych użytkowników przy wysyłaniu listy kontaktów do serwera (gophi/w) // 2004-02-11 - dodatkowe opcje dotyczące kolorów (goblin/w) - poprawka segfaulta przy wychodzeniu (goblin/w) // 2004-02-01 - dodanie wpisu ,,ncurses_timestamp'' w tematach wyglądu (*/w) // 2004-01-25 - poprawka klawiszy Home i End w FreeBSD (deli/w) // 2004-01-22 - poprawka działania auto_conference (joshua/sz) // 2004-01-13 - usunięcie użytkownika nie usuwa go z listy ignorowanych i blokowanych (perry/w) // 2004-01-12 - kod błędu GG_FAILURE_NEED_EMAIL jest zwracany w stanie GG_STATE_READING_REPLY (chilek) // 2004-01-06 - /passwd nie zmienia zmiennej ,,email'' (sgurgacz/w) // 2003-12-28 - poprawka opisu protokołu (JAJAJA/w) // 2003-12-22 - poprawka segfaultu przy wielolinijkowych wiadomościach (nyarlath/w) - obsługa locali przy sortowaniu listy kontaktów (rmrmg/w) // 2003-12-21 - poprawka ,,auto_back'' i ,,auto_away_keep_descr'' (s_wilk/sz) // 2003-12-20 - poprawka szukania nieprawidłowych nicków w liście kontaktów (adderek/w) // 2003-12-02 - poprawki związane z ,,auto_away''. dodanie zmiennej ,,auto_away_keep_descr'' (s_wilk/sz) // 2003-11-27 - dopełnianie opisów bez cytowania (*/sz) // 2003-11-22 - dodany kod błędu GG_FAILURE_NEED_EMAIL przy zdarzeniu GG_EVENT_CONN_FAILED (chilek) - zmienna auto_conference (joshua/sz) // 2003-11-20 - poprawka /find dla użytkowników ze spacją w nazwie (pi/sz) // 2003-11-19 - poprawka /dcc list dla dużych plików (?/sz) - prosta obsługa grup w ignore/unignore (sz) - zdarzenie dccfinish. możliwość usuwania nie tylko ze względu na numer zdarzenia (struthio/sz) // 2003-11-14 - libgadu: podbicie wersji ABI (porridge/w) // 2003-11-05 - dopełnianie opisów w komendach /away itp. (szok,przemmaj/w) // 2003-11-03 - zmiany stanu bez opisów nie będą logowane przy ,,log_status'' równym 2 (brat.lukasz/w) - libgadu: gg_notify*() z pustą listą kontaktów wyśle pakiet GG_LIST_EMPTY (grzegorz.sowa/w) // 2003-10-30 - ,,/last user'' też działa (joshua/sz) // 2003-10-27 - ocr tokenu (acze/w) // 2003-10-26 - libgadu: poprawka blokowania libgadu przy rozłączeniu (FIG/w) // 2003-10-21 - poprawka obsługi segfaultów (porridge/w) - poprawka czyszczenia okna i ,,(more)'' (theKnight/w) // 2003-10-20 - zmiana '\n' w opisach stanów na '|' (s_wilk/w) - libgadu: porządki z wątkowanym resolverem (sz/w) // 2003-10-19 - libgadu: wyświetla prawidłowy powód błędu przy nieudanym połączeniu SSL (w) // 2003-10-17 - libgadu: dodanie funkcji gg_image_reply() (w) - libgadu: drobne poprawki kodu (w) - dodanie komend testowych /_imagemsg (wysyła wiadomość zawierającą tylko obrazek), /_imagereq (wysyła żądanie obrazka), /_imagesend (wysyła obrazek) (w) // 2003-10-15 - libgadu: poprawka api odbierania obrazków (w) - libgadu: usunięcie leaków przy zdarzeniach GG_EVENT_NOTIFY60 i _STATUS60 (w) - poprawka czytania cudzej pamięci w /add (w) - poprawka dokumentacji protokołu (w) - libgadu: poprawka pracy na maszynach BE (speedy/w) - libgadu: dodanie zdarzenia GG_EVENT_DCC_ACK po zaakceptowaniu połączenia przez drugą stronę (Chilek/w) // 2003-10-13 - libgadu: bardzo eksperymentalna obsługa wiadomości graficznych w docs/api.txt (w) // 2003-10-09 - poprawka segfaultu w gg_free_session() z wątkami (Chilek/w) // 2003-10-08 - poprawka zapisu tokenu na dysku (porridge/w) // 2003-10-06 - przywrócenie opisu pakietów GG_STATUS i GG_NOTIFY_REPLY (trzcionkowski/w) - libgadu: poprawka segfaulta przy pobieraniu listy kontaktów (Chilek/w) - uaktualnienie opisu protokołu o obrazki w wiadomościach (w) - dodanie testowej komendy /_hexmsg, która wysyła wiadomość o treści podanej w kodzie heksadecymalnym (w) - libgadu: dodanie do pliku nagłówkowego struktur dotyczących obrazków (w) - libgadu: dodanie zdarzenia GG_EVENT_IMAGE_REQUEST, gdy rozmówca prosi o przesłanie obrazka (w) // 2003-10-05 - libgadu: poprawka wysyłania listy kontaktów na serwer (Chilek/w) - libgadu: dostosowanie wysyłania hasła do GG 6.0 nową funkcją gg_remind_passwd2() (Chilek/w) - libgadu: poprawka zmiany hasła (w) - libgadu: inteligentne potwierdzenie eksportu listy kontaktów (Chilek/w) // 2003-10-04 - możliwość wyłączenia linkowania z libbind, mimo że jest zainstalowane (arekm/w) // 2003-10-03 - libgadu: poprawka kodowania adresów e-mail w urlach (Chilek/w) - libgadu: uaktualnienie usuwania konta do protokołu GG 6.0 (Chilek/w) // 2003-10-01 - poprawka wykrywania libjpeg (embe/w) // 2003-09-30 - poprawienie zachowania się /set dla irssi_set_mode == 1 (weirdo/wysek) - libgadu: poprawki zmiennych ze znakiem i bez znaku, które są potencjalnie niebezpieczne dla użytkownika (gj/w) - libgadu: usunięcie funkcji nieaktualnych ze względu na zmiany w protokole. przeniesiono je do pliku lib/obsolete.c (w) - libgadu: poprawka wysyłania i pobierania listy kontaktów z serwera (Chilek/w) - libgadu: pobieranie tokenu za pomocą funkcji gg_token(). zwróconą strukturę obsługiwać przez gg_token_watch_fd(). po zakończeniu w ->body mamy plik graficzny o rozmiarze ->body_size, w ->token->width i ->token->height wymiary obrazka, w ->token->length długość tokenu i w ->token->tokenid jego identyfikator (w) - libgadu: poprawki obsługi http, by można było odbierać dane binarne (w) - poprawki w dokumentacji (w) - poprawka flag kompilacji pythona (ksmigrod/w) - libgadu: uaktualnienie rejestracji i zmiany hasła (w) - dodanie komendy /token pobierającej token z serwera (w) - uaktualnienie opisu api (w) // 2003-09-21 - nowa zmienna irssi_set_mode, jeśli ustawiona na 1, to zmienia zachowanie /set z jednym argumentem. domyślnie wyłączone. więcej w docs/vars.txt (wysek) // 2003-09-14 - libgadu: poprawka segfaulta (Chilek/wysek) // 2003-09-12 - libgadu: wysyłanie listy kontaktów już działa (Chilek/w) // 2003-09-11 - libgadu: obsługa listy kontaktów na serwerze zgodnej z GG 6.0. wysyłanie jeszcze nie działa prawidłowo (w) - libgadu: logowanie się za pomocą pakietu GG_LOGIN60 (w) // 2003-09-10 - włączenie gałęzi GG6 do głównej (w) // 2003-09-09 - jeśli ustawiona jest zmienna ,,EKG_NO_TITLE'', to nie będzie zmiany tytułu okna xterm'a (sz) - dokumentacja dla ekglogs. kosmetyka manuali ekg (porridge/sz) - uaktualnienie arim.theme (arim/sz) // 2003-08-27 - usunięcie nieaktualnych informacji, nowe rodzaje pakietów w GG 6.0, indeks pakietów (*/w) // 2003-08-26 - uaktualnienie ekg_logs (Goblin/w) - libgadu: poprawka zwalniania zasobów gg_session przy wątkowanym resolverze (ppluciennik/w) - libgadu: poprawka błędu typu DoS. wysyłając wiadomość niezakończoną znakiem '\0', można było rozłączyć ekg (NEMO/w) // 2003-08-05 - dodanie obsługi nowego formatu pliku do WAP (serek/sz) // 2003-07-23 - poprawka wyświetlania nazwy programu w tytule okna xterma (?/w) // 2003-07-22 - poprawka segfaulta przy czytaniu/pobieraniu uszkodzonej listy kontaktów (w) - kosmetyczne poprawki związane z dosłownym użyciem znaku '%' w niektórych miejscach (savage,w/sz) // 2003-07-14 - kosmetyczna poprawka działania polecania /dcc get (struthio/sz) // 2003-07-09 - libgadu: poprawka zapisu opcji pthread dla pkgconfig (w) - poprawka obsługi listy kontaktów z oryginalnego klienta (gamster/w) // 2003-07-07 - libgadu: poprawka błędu znaku przy dcc (joshua/w) // 2003-07-06 - poprawka wykrywania OpenSSL (perry/w) // 2003-07-03 - poprawka obsługi zdarzeń w pythonie (rmrmg/w) - dodanie show_status_{header,footer} i %} w tematach (viraptor/w) - poprawka segfaulta przy mieszaniu historią poleceń (Goblin/w) // 2003-07-02 - informacja o błędach przy logowaniu (*/w) // 2003-07-01 - poprawka zapisywania plików konfiguracyjnych (porridge/w) - poprawka wykrywania niestandardowych instalacji openssl (zawirek,adrians/w) - poprawne zamykanie deskryptora w niektórych sytuacjach (mirqus/sz) // 2003-06-30 - nie wywraca się, gdy dostanie wiadomość graficzną (sz) // 2003-06-29 - ekgbot w contrib/scripts/ (sznik/w) - kolejna przeglądarka logów, tym razem w C (Goblin/w) - linki.py w contrib/scripts/ (rmrmg/w) - pomijanie tylko dla przyjaciół w wynikach szukania (Struthio/w) // 2003-06-27 - poprawka dopełniania /python (rmrmg/w) - poprawka zapisu plików konfiguracyjnych (porridge/w) - libgadu: poprawne zwalnianie pamięci w sytuacjach kryzysowych (scooty/w) - dodanie %| do tematu pasku stanu, który dopełnia do końca linii (ptar/w) // 2003-06-24 - przepisanie wykrywania ncurses, żeby działało dobrze przy crosskompilacji. używa teraz AC_CHECK_HEADERS, zamiast sprawdzania obecności plików (pliszka/w) - poprawka tematu ostatniej obecności (rmrmg/w) - libgadu: niezainicjowana zmienna mogła powodować wywrotki w fazie łączenia na systemach, gdzie strerror() potrafi zwrócić NULL, np. SunOS (w,sz) // 2003-06-23 - poprawki crosskompilacji (pliszka/w) // 2003-06-22 - dodanie informacji o kompilacji rtg (struthio/w) - ekg nie usuwa użytkowników bez podanego numeru z listy kontaktów (a.latanski/w) - lepsza obsługa padniętego katalogu publicznego (w) // 2003-06-21 - dodanie skryptu contrib/ekglog.pl (fixer/w) // 2003-06-20 - lista kontaktów obsługuje adres e-mail (a.latanski/w) // 2003-06-18 - /list w oknie pokaże informacje o rozmówcy (weirdo,FIG/w) - poprawka wyszukiwania z --all (lukzg/w) - poprawka zachowania back_reason przy uruchamianiu ekg (a.latanski/w) // 2003-06-17 - usunięcie opcji --disable-debug z configure. sprawia tylko problemy (w) - poprawka kompilacji z -DGG_DISABLE_DEBUG (theKnight/w) // 2003-06-16 - poprawka ignore_unknown_sender (Kamil/sz) // 2003-06-11 - poprawka /exec -B do osoby ze spacją (Sydney/w) - /reload nie uaktualnia naszego stanu (FIG/w) // 2003-06-10 - uaktualnienie irc.theme, dodanie tohver.theme (Tohver/w) // 2003-06-08 - dodanie /python restart, które restartuje interpreter (rmrmg/w) - poprawka opcji --control-pipe (kosmoski/w) // 2003-06-02 - ,,ignore_unknown_sender'' nie ignoruje wiadomości systemowych (sz) // 2003-05-30 - testowa poprawa wydajności wyświetlania - nie odświeża w obrębie jednej komendy, widać to np. przy /help (w/sz) - w /last można połączyć ze sobą wszystkie opcje i zrobić np. ,,/last -u szalik -p 17:30-19:00 -n 3'' i dodać ,,-c'', aby te wiadomości usunąć (sz) - podobna kosmetyka j.w. dla /queue (sz) // 2003-05-29 - Ctrl-W wrzuca do yankbuffera (w/sz) - automagiczne szukanie nieznajmoych, zmienna ,,auto_find'' (mateusza/sz) - zdarzenie ,,conference'' (pmb/sz) - zmienna ,,ignore_unknown_sender''. wrr. w /ignore byłoby za dużo do mieszania, żeby to osiągnać. (sz) - nie trzeba usuwać użytkownika z listy ignorowanych, aby dodać kolejny poziom (sz) - status wykonanego polecenia /exec nie powinien się już nigdy pojawić zanim cały wynik polecenia nie zostanie wyświetlony (?/sz) - ekg pamięta, z jakim opisem i adresem IP ostatnio kogoś widział (joshua/sz) - zmienna ,,wap_enabled''. niezapisywanie do WAP własnych wiadomości, niezależnie od ustawień ,,display_sent'' (serek/sz) - lekka zmiana zachowania /last, może teraz pokazać wiadomości z danego przedziału czasu (sz) - informacja o obcieciu szyforwanej wiadomości (sz) // 2003-05-28 - libgadu: poprawka wątkowego resolvera przy połączeniach http (sz) - psujący zabawę błąd off-by-one w ioctld. przywracanie początkowego stanu diod LED. niestety, nie mam jak sprawdzić na Linuksie (sz) // 2003-05-21 - poprawka /disconnect przy auto_reconnect != 0 (scooty/w) - libgadu: poprawka kompilacji z GG_DEBUG_DISABLE (pikov/sz) // 2003-05-20 - poprawka segfaulta przy /set server "" (tiroy/w) // 2003-05-19 - poprawka kompilacji z ioctld (Charvel/w) // 2003-05-18 - drobne usterki w opisie protokołu (scooty/w) - poprawka zawijania (FIG/w) // 2003-05-17 - ,,sms_away'' może także działać, gdy jesteśmy niewidoczni (sz) - zmienna ,,save_question'' (Tohver/sz) - logowanie wysłanych smsów (scooty/w) - przy ui-none zamyka terminal (fidor/w) // 2003-05-16 - libgadu: gg_session->port jest prawidłowo wypełniane (w) - poprawka server_save dla połączeń TLS (perry/w) - leak w aliasach (sz) - pozbycie się strcat(), strcpy() i sprintf(). w OpenBSD są brzydkie warningi (sz) - poprawka dopełniania, aby dopełniało dobrze np. użytkowników ,,piotr_nowak'' oraz ,,piotr kowalski'' (sz) - informacja o szyfrowanym połączeniu w /status (scooty/w) // 2003-05-15 - libgadu: obsługa połączeń szyfrowanych TLSv1. wystarczy podać konkretny serwer i ustawić ,,gg_login_params->tls = 1''. oczywiście wypadałoby mieć zainstalowaną bibliotekę OpenSSL w systemie. ABI i API są zgodne poza zmianą deklaracji wewnętrznej funkcji gg_send_packet(). można sprawdzić istnienie stałej __GG_LIBGADU_HAVE_OPENSSL, żeby mieć pewność, czy dana wersja libgadu obsługuje TLSv1 (w) - libgadu: podbicie wersji API (w) - obsługa połączeń szyfrowanych TLSv1. należy podać adres serwera poprzedzony tekstem ,,tls:'' (w) - usunięcie leaka w obsłudze procesów potomnych (scooty/w) - korzystanie z hub do połączeń TLS (,,/set server tls'') (w) - libgadu: podbicie wersji klienta do 5.7.0b116 i protokołu do 0x1c (w) - uaktualnienie opisu protokołu w kwestii połączeń TLS (w) // 2003-05-14 - poprawka helpa /dcc (jojo/w) - poprawka dopełniania nazw plików (jojo/w) // 2003-05-10 - poprawka obsługi polskich liter w /find (FIG/sz) - poprawka wyboru opisów z plików *.reasons - lepiej losuje i nie wywraca się przy pustym pliku (sz) // 2003-05-05 - niedostępność osób nie będzie wyświetlana przez ,,events_delay'' sekund od połączenia (lordzik/w) // 2003-05-01 - po utracie terminala kończy pracę (tokugawa/w) // 2003-04-30 - opis instalacji w katalogu domowym dla nowej wersji autoconfa (w) // 2003-04-29 - /list pokazuje, kiedy ostatnio widziano użytkownika (qbq/w) // 2003-04-28 - libgadu: obsługa wznawianych transferów plików (Chilek/w) - dodanie polecenia ,,dcc resume'' do wznawiania przerwanych transferów (w) // 2003-04-26 - poprawka wyciszania komendy /alias -a (sz) // 2003-04-23 - poprawka zachowania trybu wielolinijkowego (theKnight/w) $Id$ ekg-1.9~pre+r2855/ChangeLog.1000066400000000000000000003611401174410337000155350ustar00rootroot00000000000000Teksty w nawiasach na końcu linii mówią o tym, kto dokonał poprawki. Jeśli jest postaci ,,nick'', powinno być jasne. Postać ,,nick/x'' oznacza, że pomysłodawcą jest ,,nick'', a zrobił to ktoś, czyjego pierwszą literą nicka jest ,,x'' (w - wojtekka, s - speedy, a - arekm, d - drg, sz - szalik). ,,p/nick'' oznacza patch lub źródło podesłane przez ,,nick'', ,,i/nick'' oznacza czyjś pomysł, ,,b/nick'' mówi, kto zgłosił błąd. // 2003-04-22 - poprawka płci przy zmianie informacji w katalogu publicznym (fixer/w) - libgadu: dodane stałe GG_PUBDIR50_GENDER_SET_{MALE,FEMALE} do ustawiania płci w katalogu publicznym. niestety stałe przy szukaniu i ustawianiu są zamienione (fixer/w) - wyświetlanie użytkowników, którzy dołączyli do konferencji (sz) // 2003-04-21 - załadowanie themu czyści cache (rmrmg/w) - libgadu: poprawka obsługi błędu pthread_create() (scooty/w) - poprawki opisu poleceń wsadowych (Lordzik/w) - poprawka konferencji, dodanie /conf --join (w) // 2003-04-20 - poprawka zachowania przy zmianie rozmiaru terminala (weirdo/w) // 2003-04-18 - poprawka zachowania /find (mateusza/w) - nieblokująca obsługa klawiatury w ncurses (FIG/w) // 2003-04-17 - poprawka /dcc list (weirdo/sz) // 2003-04-16 - kosmetyka wyświetlania wiadomości w readline (Lordzik/sz) - poprawka warninga przy kompilacji bez ncurses (Lordzik/w) - poprawka komunikatu błędu przy błędzie ładowania themu (gozda/w) - poprawka debugowania w readline (Lordzik/w) // 2003-04-15 - /reconnect nie psuje opisu. zostaje on bez zmian, niezależnie od ustawień zmiennej ,,keep_reason'' (sz) - nie działa już wyświetlanie stanu osób z trybem ,,tylko dla znajomych'' podczas wyszukiwania. to było do przewidzenia :) (sz) // 2003-04-14 - libgadu: poprawka obsługi błędów w gg_read_line() (jajcus/w) - kropka na początku nazwy pliku zamieniana na '_', żeby nie nadpisać przypadkiem ważnych plików konfiguracyjnych (jojo/w) // 2003-04-12 - poprawka wielolinijkowych komend przez pipe (mateusza/w) // 2003-04-11 - usunięcie kilku małych leak'ów (sz) - kosmetyka pomocy dla komendy /add (FIG/sz) - ekg respektuje zapis userlisty od wersji 4.9.3 oryginalnego klienta i nie gubi zapisywanych tam informacji (e-mail, dźwięki). obecnie są one po prostu przechowywane; może po wydaniu 1.0 zrobi się z nich użytek (sz) // 2003-04-10 - kosmetyka - polecenie /python korzysta z własnych formatów (sz) // 2003-04-09 - poprawka polskich liter w opisach (sz) - wspomnienie w README o konfiguracji za pomocą zmiennych i polecenia /set, bo chyba nie zawsze było to oczywiste (sz) - dokładniejszy opis logów w dokumentacji, logowanie portów (Chilek/w) - poprawka Entera wielolinijkowych (w) - poprawka informacji o dcc z samym sobą (wojtuś/w) - dodanie zmiennej ,,dcc_limit'' określającej limit połączeń w danym przedziale czasu. domyślna wartość to 30 połączeń na 30 sekund. potem zostaje wyłączone dcc, żeby ekg nie dało się ubić (w) - dodanie Alt-A -> /window active. jednolinijkowe patche, które komuś mogą pomóc, a nie szkodzą, chyba nie powinny czekać miesięcy na wydanie 1.0 (gozda/w) // 2003-04-08 - poprawka segfaulta w readline przy dopełnianiu nazw plików, gdy brak funkcji ,,rl_filename_completion_function'' (sz) - poprawka stanów opisowych zawierających znaki poniżej 32 (adaml/w) // 2003-04-07 - libgadu: poprawka pthreadów w libgadu.pc (jajcus/w) - poprawka zawijania wiadomości przy niestandardowych timestampach (mp/o) - ekg nie wysyła już niepotrzebnie zmiany stanu po zalogowaniu, dzięki czemu Kadu nie wykrywa niewidzialności (scooty/w) - poprawka tajemniczego błędu 'handle_command_line' w pythonie (sznik,sz/w) // 2003-04-06 - kosmetyka ekl2.sh (porridge/sz) - ,,/ignore notify'' spowoduje też, że użytkownik, przy zmianie stanu, nie zostanie dopisany do listy dopełniania Tabem (kbns/sz) // 2003-04-05 - dalsze kosmetyczne poprawki reakcji na zmianę rozmiaru terminala w readline i ncurses. komenda ,,_resize'', jeśli nie możemy obsługiwać zmian automagicznie (sz) - deaktywacja systemowego znaczenia klawiszy Ctrl-C, Ctrl-Y itp. w ncurses (sz) // 2003-04-03 - poprawka reakcji na zmianę rozmiaru terminala (sz) - poprawka segfaulta przy wyjściu z ekg z załadowanym skryptem pythona, który pisze coś w deinit() (embe/sz) // 2003-04-02 - libgadu: poprawka konferencji na bigendianach (pmb/sz) - przy wysyłaniu smsów zamyka się stdin, żeby przypadkiem interaktywna aplikacja nie zepsuła ekg (w) - komendy wysyłane przez rurkę rozumieją \ na końcu linii jako przejście do kolejnej (mateusza/w) // 2003-04-01 - libgadu: wywołanie gg_watch_fd() w stanie GG_STATE_CONNECTING_GG i z session->timeout == 0 spowoduje połączenie z kolejnym portem (Ron_K/w) - poprawka błędów przy wielokrotnym ,,/dcc get'' (ubanus/sz) - poprawka ekg -b przy włączonym back_reason (jojo/w) // 2003-03-30 - uruchomienie interatywnej aplikacji nie blokuje ekg (ubanus/w) - /play działa jak /exec sound_app, dzięki czemu zadziała modprobe w przypadku braku odpowiednich modułów (ubanus/w) - keep_reason == 2 nie zapisuje stanu (Tohver/w) - Alt-Backspace działa w ncurses (porridge/w) - poprawka Backspace w wielolinijkowych (embe/w) // 2003-03-29 - poprawka Ctrl-W (w) - ucinanie zbyt długich szyfrowanych wiadomości (sz/w) - poprawka segfaultów przy wysyłaniu długich wiadomości (w) - poprawka Ctrl-Spacja (mateusza/w) - zamiana ,,dcc send --reverse'' na ,,dcc rsend'' i ,,dcc voice --reverse'' na ,,dcc rvoice'' (FIG/w) - poprawka Shift-Enter w xtermopobnych (*/w) // 2003-03-28 - libgadu: usunięcie starych stałych i nazw struktur zachowanych dla kompatybilności ze nieaktualnymi wersjami API (w) - drobna poprawka do licencji pozwalająca kompilować, konsolidować i uruchamiać ekg z biblioteką OpenSSL (porridge/w) - drobne poprawki readline. niech wygląda jako tako w 1.0, mimo że już nie supportowane: operator $, window active/last, msg * (sz) - sekwencje z Alt'em w readline zawsze odnoszą się do małych liter (sz) - kosmetyczna poprawka jednoczesnego użycia parametrów --stime i --number w /last (sz) // 2003-03-27 - poprawki zachowania interfejsu readline (porridge/sz) - drobne uzupełnienie dopełniania Tabem w readline (sz) // 2003-03-26 - usunięcie leaka w aliasach (w/sz) - poprawka wpisywania kolorów (pmb/w) // 2003-03-25 - zmiana nazw ukrytych poleceń z _add/_del na _addtab/_deltab (sz) - poprawki wymawiania tekstu. nie blokuje, nie gubi tekstu, buforuje, gdy nie może wypowiedzieć w danej chwili. dodanie głupiego polecenia /say, głownie dla opcji ,,--clear''. w ogóle, ktoś tego używa? (sz) // 2003-03-24 - kosmetyka komunikatów o błędach przy /ignore i /block (sz) - przeniesienie obsługi logowania i /last do log.c (sz) - poprawka dokumentacji zmiennych (embe/w) - rozmowy głosowe działają z GG 5.0.5 (w) // 2003-03-23 - konsekwentne zachowanie przy aliasach ze spacją (tokugawa/sz) - poprawka dokumentacji zmiennych (embe/w) - przy uruchomieniu ekg powód będzie ustawiany zgodnie z ustawieniami (embe/w) // 2003-03-22 - poprawka /add -f (embe/sz) - poprawka wielokomendowych aliasów z formatami %1...%9 (sz) // 2003-03-21 - drobne literówki (FIG/sz) - libgadu: naprawienie błędu wysyłania plików z libgadu do GG -- po zakończonym transferze GG wyświetlało błąd transferu (w) - sensowniejszy termin ,,motyw'' zamiast ,,opis wyglądu'' (rmrmg/w) // 2003-03-20 - zmiana domyślnych wartości zmiennych: contacts = 2, display_ack = 3, display_sent = 1, make_window = 2 (sz/w) - dodanie podstawowych informacji o obsłudze klienta przy pierwszym uruchomieniu (sz/w) // 2003-03-18 - ,,/_descr -'' prawidłowo wyłącza stan opisowy (sz) - poprawki dokumentacji (w) - poprawki literówek w dokumentacji (FIG/w) - poprawka obsługi kolorowych wiadomości (sz/w) // 2003-03-17 - docs/protocol.html zgodne z XHTML 1.0 Transitional (w) - zmiana nazwy komendy /_status na bardziej intuicyjną /_descr (sz/w) // 2003-03-16 - libgadu: kolejna poprawka kompilacji na bigendianach (speedy/w) - dodanie komendy /_status zmieniającej tylko opis stanu (mkanski/w) // 2003-03-15 - poprawka kompilacji ui-readline (charvel/sz) - kosmetyka kilku rzeczy, żeby nie tworzyć nowych katalogów w ~/.gg przy pomyłce w parametrze ,,-u'' podczas startu (sz) - poprawka zapisywania konfiguracji z profili (pirat/sz) // 2003-03-14 - kosmetyka własnego stanu (gozda/sz) - prostsza obsługa ścieżki ,,config_dir'' w przypadku profili. mamy prawdziwe ściezki po segfault/oom (sz) - kosmetyka i uproszczenie zachowania widzianego przez usera w przypadku segfault/oom (sz) // 2003-03-12 - mówimy papa sim, zostaje simlite (w/sz) - poprawka zachowania /window last (khhh/sz) - libgadu: poprawki dla bigendianowych maszyn (gs/w) - poprawki leaków (w) - poprawne wyświetlanie tabów w ui-ncurses (w) // 2003-03-11 - libgadu: poprawki dokumentacji (w) // 2003-03-10 - poprawiona kompilacja ui-readline (Charvel/w) - dodanie /window last (cowboy/w) - usunięcie informacji o pływających oknach z pomocy. bez sensu się w nie bawić przed 1.0. więcej z nimi kłopotów, niż pożytku. jeśli ktoś chce to są, ale nieudokumentowane (sz?/w) - libgadu: uaktualnienie skryptu generującego dokumentację o typedefy i enumeracje (w) - libgadu: poprawka wiadomości systemowych (sz/w) // 2003-03-09 - zmienna ,,mesg'' zamiast ,,mesg_allow'' i jej poprawki (sz) - kosmetyka kilku drobiazgów związanych z ,,$'' (sz) - poprawka kompilacji pythona (sz,embe/w) - kosmetyka configure.in, prosimy zapiąć pasy (w) // 2003-03-08 - ,,$'' w miejscu ,,numer/alias'' będzie zastąpione w każdej komendzie aktualnym rozmówcą (sz) - libgadu: poprawki kompilacji z pthreadami (w) - porządki w kodzie, wydzielenie śmieci ze stuff.c (w) // 2003-03-07 - uporządkowanie #include'owanych plików, dodanie potrzebnych, usunięcie zbędnych. inne kosmetyczne zmiany. pozbycie się warningów na niektórych systemach (sz) - libgadu: maksymalna długość opisu (GG_STATUS_DESCR_MAXSIZE) to 70 znaków (*/sz) - usunięcie ,,fade_in'' (w/sz) - libgadu: dodanie zmiennej ,,gg_debug_handler'' pozwalającej przejąć wywołania gg_debug() (hao/w) - libgadu: wyeksportowanie funkcji gg_vsaprintf() i zmiennej gg_debug_file (w) - libgadu: dodanie funkcji gg_register2(), gg_unregister2() i gg_change_passwd3() obsługujących protokół GG 5.0 (w) - uaktualnienie opisu protokołu (w) - komenda /passwd nie wymaga adresu e-mail (wojtuś/w) - komenda /unregister wymaga podania numeru i hasła, żeby zabezpieczyć się przed przypadkowym usunięciem konta (w) - komenda /change już działa (w) // 2003-03-06 - libgadu: dodanie funkcji usuwania listy kontaktów z serwera (wysek?/w) // 2003-03-04 - poprawka /find bez parametrów w oknie z rozmówcą (embe/sz) // 2003-03-03 - poprawka /python exec bez parametru (sz) - poprawka np. /exec -b $ w przypadku bindowania (krzyk/sz) - bezpieczniejsze wywoływanie timerów, gdyby czasem miał on sam siebie usuwać... tak na wszelki wypadek ;> (sz) // 2003-03-02 - nowe man'y dla ekl2 (porridge/sz) - generowanie kluczy dla SIM na maszynach bez /dev/urandom (sz) - zabezpieczenie podczas wykonywania aliasu na wypadek, gdyby alias sam siebie usuwał (sz) // 2003-03-01 - poprawka ,,odszyfrowywania'' wiadomości systemowych w sim.c (pmb/sz) // 2003-02-28 - /last -n (joshua/sz) // 2003-02-27 - poprawka przewijania okna (FIG/w) - poprawka segfault'a przy /reconnect po usunięciu zmiennej ,,proxy'' (sz) // 2003-02-26 - poprawka kompilacji pod Cygwin'em (Sydney/sz) - update krzyk.theme (krzyk/sz) - poprawki zachowania niektórych formatów w statusbarze (krzyk/sz) - poprawka odczytu z listy kontaktów blokowanych/ignorowanych niewidocznych jawnie na liście (FIG/sz) - libgadu: poprawka przesyłania plików na bigendianach (sz) // 2003-02-25 - możliwy segfault, gdy ignorujemy kogoś, kogo nie mamy na liście (FIG/sz) - poprawka compat/scandir.c, żeby działało dobrze na SunOS 5.8, gdzie w ,,struct dirent'' mamy d_name[1] (sz) - nasz adres i port dla dcc zmienia się na liście dopiero po /reconnect, co bardziej odpowiada rzeczywistości (sz) - mea culpa - przez kilka dni nie działało dobrze odczytywanie listy kontaktów eksportowanej z gg 4.6.3 i nowszego (sz) - segfault przy /dcc close (sz) - poprawka wysyłania konfiguracji na serwer (zmienne VAR_MAP) (sz) - poprawki sim oraz simlite: żeby działały dobrze na maszynach bigendianowych oraz tam, gdzie nie ma /dev/urandom (sz) // 2003-02-24 - pozbycie się kosmicznych warningów (sz) - bardziej zrozumiałe zachowanie przy make_window = 1 (sz) - poprawka segfault'a przy /list -G (sz) - /list pokaże też, że ktoś jest za firewall'em lub nie ma nas w kontaktach. trochę zbędne, bo można ten fakt stwierdzić i bez tego... (spaceman/sz) // 2003-02-23 - /window active (sz) - kosmetyczne poprawki /dcc (sz) - odszyfrowywanie wiadomości od ignorowanych przy ,,log_ignored = 1'' (sz) - poprawka wyświetlania własnego stanu przy włączonym trybie ,,tylko dla znajomych'' (sz) // 2003-02-22 - w aliasach mogą występować formaty %1...%9, dzięki czemu można dowolnie ustawiać sobie przekazywane parametry (sz) - delikatna normalizacja promptów w standardowym temacie (sz) // 2003-02-21 - szyfrowanie działa także wtedy, gdy wysyłamy do wielu osób za pomocą /msg (sz) - /msg oraz /chat z adresatem wiadomości w postaci ,,*'' roześle do wszystkich aktualnych rozmówców (rmrmg/sz) - drobne korekty dokumentacji (sz) // 2003-02-20 - poprawka segfault'a przy braku niektórych zmiennych w pliku konfiguracyjnym (a.latanski/sz) - mała poprawka /quit, żeby zachowywało się _dokładnie_ tak jak komendy zmiany stanu, w zależności od zmiennej ,,keep_reason'' (sz) // 2003-02-19 - dopełnianie uin'ów z listy kontaktów (sz) - usunięcie ui-automaton (ok malekith@pld-linux.org/sz) - ,,-'' przy /quit i /disconnect usuwa opis permanentie tak, jak to robią /away, /back czy /invisible (sz) - /disconnect pamięta opis przy włączonym ,,keep_reason'' (Brzezi/sz) - poprawka warning'ów kompilacji z iocltd (pmb/sz) - poprawki window next/prev, żeby bardziej uważało na plątające się gdzieniegdzie okienka pływające (andylm/sz) - nie tworzymy niepotrzebnie nowych okien, na przykład przy ,,chat numer'', a później ,,chat alias'' (pmb/sz) // 2003-02-18 - ,,fade_in'' jest domyślnie wyłączone (ubanus,w/sz) - uaktualnianie timeout'ów sesji nie częściej niż raz na sekundę, żeby timeout timeout'owi był równy (sz) - poprawka wczytywania pojedynczych zmiennych, m.in. ,,fade_in'' i ,,interface''. ta ostatania nie była zawsze zapisywana. teraz odbywa się to automagicznie po uruchomieniu ekg z opcją -f (sz) - kosmetyka dcc. standardowo więcej informacji w /dcc list. pełniejszy komunikat o timeout'cie połączenia (sz) // 2003-02-16 - usunięcie leak'a w /exec (sz) - zapisanie opcji dla /exec wielkimi literami spowoduje dodanie polecenia do wysyłanego wyniku. czasami się przydaje ;> (sz) - dokładne czysczenie formatów po ,,/set -theme''. problem był na przykład z wyłączeniem tematu ircopodobnego (sz) // 2003-02-15 - głupia ja - poprawka poprawki timestamp'ów (sz) - poprawka window next/prev (sz) - nie pozwalajmy na podanie konfliktowej wartości zmiennej w postaci liczby (sz) - libgadu: dodanie atrybutu ,,printf'' do funkcji gg_saprintf(), dzięki czemu kompilator będzie sprawdzał poprawność jej parametrów (w) - libgadu: drobne poprawki parametrów gg_saprintf() (w) - ekg: j.w. do funkcji saprintf() (w) - libgadu: obsługa fragmentacji nagłówków pakietów (speedy/w) - poprawka nazwy struktury w opisie protokołu (solaris/w) // 2003-02-14 - dżwięki przy zmianach stanu zachowują się tak, jak to nakazuje zmienna ,,display_notify''. nie są natomiast wyłączane przy ukrywaniu zmian poprzez ,,contacts'' równe 2 (sz) - poziom ignorowania ,,notify'' (sz) - mniej rażący w oczy theme dla nazwy grupy w liście kontaktów (sz) - ,,stderr'' wędruje do aktualnego okna (w/sz) - poprawka powtórzeń zmiany stanu, gdy w opisie były polskie literki (sz) - zabezpieczenie przed zalewem połączeń dcc (segfault/w) - libgadu: wypełnianie wszystkich pól file_info przy wysyłaniu pliku (Chile/w) // 2003-02-13 - lepsze wykrywanie pthread (adrians/w) - drobna kosmetyka: ignorowanie spacji po przecinku w ,,contacts_groups'' oraz prawidłowe dopełnianie przy aliasach do komend z backslashem na początku (sz) // 2003-02-12 - skrypt autorun/__init__.py nie jest ładowany (rmrmg/w) - poprawka segfaulta przy ,,python unload'' bez parametrów (rmrmg/w) - mała reorganizacja komend /timer i /at. ta ostatnia potrafi już ,,na stałe'' planować komendy (sz) - krzyk.theme (krzyk/sz) - poprawka wyciszania /sms (sz) - poprawka zapisu układu okienek (sz/w) // 2003-02-11 - poprawka przewijania okien (sz/w) - poprawka segfaulta przy oknach pływających (lordzik/w) - /window new nie tworzy więcej niż jednego okna o danej nazwie (ember/sz) - poprawka zmiennej ,,interface'' (a.latanski/w) // 2003-02-10 - poprawka duuużych marginesów okna (sdas/w) - zmienna ,,events_delay'' dotyczy również dźwięków (rmrmg/w) - poprawki sprawdzania, którego timestampu użyć w /status i wiadomościach. w wyjątkowych przypadkach (np. gdy włączenie/połączenie ekg nastąpiło kilka minut po północy) z powodu małej precyzji, dochodziło do pomyłek (sz) - /add alias robi użytek z dodatkowych opcji dotyczących wpisu (sz) - s/gg_remove_notify/gg_remove_notify_ex, żeby nie zostawiać śmieći np. po usunięciu z listy osoby, którą blokujemy (sz) - ekg ostrzega o możliwości filtrowania wiadomości przez serwer (joshua/w) - informacja dla nowych użytkowników o konieczności podania adresu e-mail (w) - zmienna ,,display_pl_chars'' działa też w nagłówku i pasku stanu (sz/w) - usunięcie informacji o zmiennej ,,debug'' (sCoOtY/w) - poprawka segfaulta przy zbyt dużym rozmiarze listy kontaktów (salvador/w) - poprawka sortowania userlisty (leon,fidor/w) // 2003-02-09 - poprawione zawijanie w liście kontaktów (pmb/w) - dodanie implementacji funkcji strlcpy/strlcat z OpenBSD. można z nich więc korzystać na każdym systemie (sz) - poprawka segfaulta przy automatycznym reconnect'cie (acze/sz) - poprawka otwierania nowych okien z nickami z '+' lub '*' na początku (K.Gibas/sz) - poprawka segfaultów i błędów z włączonym sort_windows (*/w) - dodanie zmiennej ,,fade_in'' (w) - poprawka przewijania ekranu w ncurses (sz/w) // 2003-02-08 - przepisanie compat/dirname.c, gdyż poprzednia wersja była na innej licencji (BSD) niż cały ekg (sz) - drobne porządki, poprawki w ustawianiu zmiennych, ,,0xF'' też jest prawidłową wartością liczbową (sz) - zbyt długa wysyłana wiadomość zostanie przycięta. niestety, nie dotyczy to jeszcze szyfrowanych wiadomości (w) - drobne poprawki kodu (w) - usunięcie zmiennej ,,contacts_descr'' (w) - kompletna reorganizacja listy kontaków. jest nowa, kolorowa, bardziej konfigurowalna, themowalna i nie szczypie w oczy. dodanie zmiennej ,,contacts_options'', warto zajrzeć do jej opisu (koniu i wiele innych osób, które dzieliły się pomysłami/w) - obsługa grup w liście kontaktów. ustawiane zmienną ,,contacts_groups'' i przełączane klawiszem F4 (jojo/w) - libgadu: bufor z opisem stanu z gg_login_params jest strdup()owany (pirat/w) - informowanie o blokowaniu lub ukrywaniu się przed kimś w /list (cukier/w) - możliwość negacji w ,,/list @grupa'' (cukier/w) // 2003-02-07 - poprawka dzielenia linii po zmianie listy kontaktów (pmb/w) - porządki i reorganizacja dokumentacji: włączenie dcc-protocol.txt do protocol.html, połączenie opisów formatów plików w files.txt, literówki i drobne poprawki dokumentacji libgadu (w) - poprawka obsługi zmiennej ,,interface'' (a.latanski/w) - dodana zmienna ,,reason_limit'' (jojo/w) - poprawki ,,reload plik'', gdy ktoś używa zarówno readline jak i ncurses (sz) - kosmetyka /change (sz) - poprawka /add -f (sz) - zmiana stanu przy starcie zachowuje się przy włączonym ,,keep_reason'' tak samo, jak w kliencie. ze względu na sposób podawania parametrów, nie można jednak wyczyścić stanu przez ,,-''. jeśli będzie to przeszkadzało, zawsze można przywrócić stare, ale chyba bardziej kłopotliwe zachowanie ;) (sz) - usunięcie zbędnego sprawdzania pod kątem ,,NULL'' w userlist.c. jeśli komuś coś sie zepsuło, krzyczeć, bo trzeba wszystkie błędy wyłapać. (sz) - poziomy ignorowania. /help ignore (sz) // 2003-02-06 - s/strcmp/strcasecmp/ w kodzie query dla ui-readline (teardrop/d) - taby w docs/vars.txt (sz) - ustawienie ,,contacts'' na wartość 2 nie oznacza wcale, że ,,beep_notify'' czy też ,,sound_notify_file'' ma przestać działać (sz) - poprawka kompilacji biblioteki dzielonej na OpenBSD (bartek/w) - poprawka obsługi zmiany rozmiaru terminala (perry/w) - jeśli terminal jest zbyt mały, lista kontaktów jest ukrywana (w) - /status pokazuje uptime klienta (FIG/w) - poprawka stylu w docs/protocol.html (w) - poprawka tymczasowej zmiany poziomu debugowania (w) - dodana komenda /_ctcp (w) // 2003-02-05 - dodanie ,,cleartab -o'' (Murphy/sz) - drobne porządki (sz) - mała poprawka precyzji /at (TycooN/sz) - sprawdzanie wartości ,,contacts_size'' (sdas/w) - libgadu: s/fix16/gg_fix16/, s/fix32/gg_fix32/ (w) - pozbycie się słowa ,,status'' z themów. następnym etapiem będzie pozbycie się słowa ,,theme'' ;) (w) - dokładniejszy opis /passwd (sz/w) // 2003-02-04 - poprawka inteligencji /timer (FIG/sz) - poprawka zdarzenia sigusr2 (krzyk/sz) - usunięcie zapomnianych śmieci (lordzik/w) - poprawka themów wiadomości (lordzik/w) - poprawka segv przy opcji -f (d) - poprawka bindowaniu w ui-readline (d) - dodanie opisu usług http do docs/protocol.html (pm/w) - dodanie opisu nowego protokołu katalogu publicznego (w) // 2003-02-03 - poprawka kompilacji przy braku openssl'a (*/sz) - zapędziłem się: on przyjmuje znów tylko jednego użytkownika/grupę. przy większej ilości trzeba by wiele rzeczy sprawdzać, a to tylko niepotrzebnie skomplikowałoby i tak już brzydki kod (z powodu małych możliwości manipulacji grupami). w ogóle to, zamiast /on lepiej użyć o wiele lepszego python'a ;> (sz) - przekazywanie liczby nowych maili w zdarzeniu ,,newmail'' (sz) - drobne poprawki dokumentacji (sz) - nie czytajmy całego pliku np. w /reload, jeśli nie wygląda to na plik z konfiguracją - po co zawieszać ekg. sam tak zrobiłem, przez przypadek dając za parametr plik wielkości 150 MB... jeśli coś pójdzie źle podczas ,,reload plik'', wczytana zostanie ponownie konfiguracja z ~/.gg/config (sz) - poprawka /blink_leds i /beeps_spk (sz) - usunięcie nieaktualnego przykładu search.c (sz) - ujednolicenie opcji --list w niektórych komendach (sz) - możliwość wyświetlania tylko wybranej sekwencji w /bind (FIG/w) - sensowna lista kluczy publicznych (FIG/w) - wykrywanie płci w wynikach wyszukiwania (FIG/w) - libgadu: usunięcie leaków w gg_pubdir50() (w) - libgadu: gg_pubdir50_add() zastępuje pole, jeśli już istnieje (w) - dodanie /find --all (*/w) - dodanie /find --stop (FIG/w) - drobna optymalizacja wyświetlania listy kontaktów (w) - obsługa klawiszy F1-F4, Home i End na głupich terminalach (czyt. Konsole z KDE 3.0, pewnie inne też), kosztem Alt-Shift-O (w) // 2003-02-02 - komenda ,,key'' do obsługi kluczy SIM (sz) - poprawka zachowania po ,,reload'' (m.in. duplikaty aliasów) (sz) - kolejna poprawka tabów podczas czytania z potoku (sz) - można podać wiele numerów/aliasów/grup jako parametr /on (sz) - wyświetlanie fingerprintu kluczy (w) - poprawka analizy parametrów klienta. rozumie już --away "powód", -a "powód" i -a"powód" (w) - drobne poprawki sztucznej inteligencji /list (w) - poprawka dopełniania (FIG/w) - ,,add --find'' doda do listy kontaktów ostatnio znalezioną osobę (w) // 2003-02-01 - poprawka Alt-9 (krzyk/w) - uaktualnienie leon.theme (leon/w) - dodana zmienna ,,proxy_forwarding'', która pozwala podać adres i port przekierowania na serwerze pośredniczącym (proxy, router, nat, cokolwiek) i mieć działające dcc. przyznaję, że nazwa nie jest najlepsza. (fidor/w) - libgadu: brakujący include w search.c (sCoOtY/w) - konwersja hasła na CP1250 podczas łączenia (Mati/w) - dodanie zmiennej ,,password_cp1250'', którą należy włączyć, jeśli serwer odrzuca hasło z polskimi literami (w) - plik /etc/ekg.conf jest ładowany _przed_ konfiguracją użytkownika, plik /etc/ekg-override.conf _po_ konfiguracji użytkownika (porridge/w) - dodanie do dokumentacji informacji o kolejności ładowania konfiguracji (w) - spore zmiany w kodzie dopełniania Tabem. prosimy zapiąć pasy i w przypadku błędów pokazać _dokładną_ linię i opis tego, co powinno się stać (w) - poprawka segfaulta przy wczytywaniu błędnego .gg/emoticons (*/sz) - w oknie rozmowy z nieznaną osobą wystarczy /add alias (krzyk/sz) - komenda reload (stforek/sz) - poprawka kodowania eksportowanej listy kontaktów (Sero/sz) - dalsza reorganizacja zdarzeń, ulepszenie logiki, opis w /help on i troche innych mniej poważnych zmian. zdarzenie ,,blocked''. zmiana ,,new_mail'' na ,,newmail'' i ,,disconnect'' na ,,notavail'' (sz) - zmienna ,,events_delay'' (sz) - usunięcie ekgsearch (sz) - poprawka wyświetlania tabów (w) - dodanie parametru do /save, który mówi, gdzie zapisać konfigurację (w) - po uruchomieniu drugiej sesji ekg nie będzie próbowało się łączyć ponownie (fidor/w) - obsługa kolorów. niestety ze względu na niewielką ilość kolorów na terminalu ANSI będą problemy z odwzorowaniem prawdziwej barwy. poza tym, mogą wystąpić problemy z atrybutami i kolorami na tym samym tekście (np. zielony i podkreślony). kolory w wysyłanych wiadomościach wybiera się przez wciśnięcie Ctrl-R i wpisaniu za tym numeru koloru (od 0 do 15). koniec kolorowej sekwencji to samo Ctrl-R. każdy kolor należy kończyć. klawisz Ctrl-R jest tymczasowy, dopóki nie znajdę sposobu na obsłużenie Ctrl-C w ncurses (w) // 2003-01-31 - drobna reorganizacja kolorów w ui-ncurses (w) - zmienna ,,display_color = 2'' wyświetla kolory wszędzie oprócz pasku stanu i nagłówka okna (Charvel/w) - nowy rodzaj okna ,,w->doodle = 1'' przeznaczony dla skryptów pythonowych. mogą rysować po nim co tylko chcą, gdzie tylko chcą i jak tylko chcą. wszystko dzięki funkcjom ekg.window_printat() i ekg.window_commit(). nie ma przewijania, nie ma bajerów. po dodaniu kilku miłych funkcji do obsługi okien z pythona będzie można tworzyć okna dialogowe. a z tego względu, że skrypty pythona mają dostęp do zmiennych... hmm, kto napisze Kreator Konfiguracji EKG? :> (w) // 2003-01-30 - bardziej precyzyjny opis zmiennej ,,auto_back'' (pmb/sz) - ekg nie pozwala na niebezpiecznie małe wartości ,,backlog_size'' (sz) - /list pokazuje nasz przycięty opis, a nie taki, który wpisaliśmy (sz) - /on pozwala na wykonanie każdej komendy ekg. akcje (beep, play) są teraz dostępne jako zwykłe komendy (sz) - parametr /exec % zamieniony na $, żeby uniknąć ew. konfliktów z formatami (sz) - nie dodawajmy do listy dopełnień przy błędnym nicku w chat/msg (sz) - taby w stderr, tyczy się to więc m.in. wyników /exec (sz) - poprawka niedziałającego string_insert_n() (sz) - poprawienie make_window = 1 (salvador/sz) - poprawka kombinacji Ctrl- na terminalach BSD (sz/w) - ignorowanie SIGQUIT, przez co Ctrl-4 i Ctrl-\ nie będą wychodzić (sz/w) - libgadu: usunięcie kodu gg_search50() (w) - libgadu: usunięcie kodu gg_search() i zastąpienie go funkcjami zwracającymi błąd (w) - poprawka klawisza End (Brzezi/w) - rewrite kodu parsowania zdarzeń dla ioctld (w) - poprawki helpów nowych komend (w) - poprawka przenoszenia atrybutów do nowej linii wiadomości (*/w) - poprawka zachowania zmiennej ,,random_reason''. teraz losuje nowy opis przy każdym połączeniu (w) // 2003-01-29 - dodanie klawisza Ctrl-K (bies/w) - poprawienie docs/protocol.html. jest zgodne z XHTML 1.0 Transitional (w) - zmienna ,,sound_mail_file'' (sz) - wzmianka o statusie ,,tylko dla znajomych'' w search50 w docs/api.txt (sz) - kosmetyka konferencji. nie tworzy kolejnych nazw #confX przy błędach. /find w oknie z konferencją wyszuka wszystkich uczestników (sz) - /bind może już przypisywać domyślne akcje klienta innym klawiszom, szczegóły w ,,/bind -L'' (w) - libgadu: dodanie funkcji gg_pubdir50_seq_set() (mmazur/w) - libgadu: podbicie wersji API (w) - reakcja na zmianę rozmiaru terminala (w) - poprawka Alt-G i zapisywania bindów (sz/w) // 2003-01-28 - uaktualnienie opisu protokołu (rano/w) - poprawka zapisywania pływających okienek (wojboj/w) - dosyć duże uproszczenie komendy ,,on'', dzięki czemu obsługuje się ją bardziej intuicyjnie (sz) - dopełnianie w /python i /on (zdarzenia) (sz) - ,,dcc list'' zamiast ,,dcc show'' (sz) - kosmetyka opisów niektórych komend w /help (sz) - można wyciszyć za pomocą ^ komendę ,,exec'' (sz) - poprawki komendy ,,exec'', żeby nie psuła escapowania (w) - libgadu: zapisywanie wykrytych includów z uintXX_t do libgadu-config.h (adrians/w) - dodanie klawisza Ctrl-V (w) - poprawka kombinacji z Altem (sz/w) - dodanie klawiszy Alt-B, Alt-D i Alt-F (bies/w) // 2003-01-27 - wyciszenie aliasu spowoduje wyciszenie komend w nim zawartych (sz) - brakujący opis wartości 4 zmiennej ,,completion_notify'' (sz) - usuwanie użytkownika z dopełnień TABem po usunięciu go z listy (sz) - poprawki w dopełnianiu utworzonej konferencji (bies/sz) - irc.theme pokazuje ircopodobnie również konferencje (sz) - ekg znów pokazuje status osób w /find, które mają włączony tryb ,,tylko dla znajomych'' (sz) - zmiana ignorowania z Alt-I na Alt-G (perry/w) - poprawne wyświetlanie wysyłanych wiadomości z atrybutami (Murphy/w) // 2003-01-26 - list alias -o/-O działają wyłącznie w trybie ,,tylko dla znajomych''. ,,help list'' o tym wspomina (sz) // 2003-01-25 - przy włączonym auto_back nie wraca ze stanu ,,zajęty'', jeśli nie był on ustawiony automagicznie (Tohver/sz) - dopełnianie blokowanych w /unblock (sz) - poprawki dopełniania uinów nieznanych osób (perry/sz) - poprawki readline (sz) - mały głupi bajer: version pokazuje czas kompilacji (sz) - usunięcie pewnego niejasnego zachowania. przy ,,private on'' ignorowanie powodowało, że ignorowana osoba przestawała widzieć nasz status - od tego jest jednak funkcja blokowania (pmb/sz) - drobne poprawki helpa i tematów /list (sz) // 2003-01-24 - wykończenie wyciszania niektórych komend (sz) - ignorowanie znaków nowej linii w opisie, niektóre klienty jabbera pozwalają na to i psuje nam to wyświetlanie m.in. /list (sz) - w zmiennej systemowej ,,EKG_DEBUG'' można umieścić nazwę pliku, do którego poleci debug (sz) - naprawienie /bind nie wczytującego konfiguracji z pliku (pmb/sz) - można wysyłać wynik exec do rozmówcy z aktualnego okna (pmb/sz) - klawisze Alt-Q do Alt-P przełączają do okienek 11..20 (gozda/w) // 2003-01-23 - dodanie ukrytej zmiennej ,,interface'' przechowującej nazwę używanego interfejsu (a.latanski/w) - możliwość wysłania komuś wyniku /exec. szczegóły: help exec (sz) - dodanie komendy _debug_dump (sz) - przywrócenie dawnego zachowania przy zmianie rozmiaru terminala. wciąż nie działa, ale przynajmniej rzadziej się wszystko wysypuje (spaceman/sz) - kosmetyka (sz) - poprawki związane z strncpy() i strncat() (sz) - poprawka kodowania argumentów /find (zuko_wski/w) - j.w. dla /change (sz) - nowe formaty /list (w) - dodanie ^ przed nazwą komendy ukryje jej wynik (w) // 2003-01-22 - poprawka zachowania przy segfault'cie (sz) - j.w. w przypadku braku pamieci (sz) // 2003-01-21 - poprawki /list (fig/sz) - uaktualnienie leon.theme (leon/sz) - window next/prev omija okno z debugiem (sz) - userlist, config, debug po wywrotce zapisywane są w odpowiednim katalogu, jeśli używamy różnych profili (sz) - jeśli ekg się wywróci, to ostatnie 50 linii z debug zapisywane jest do ~/.gg/debug.PID (sz) // 2003-01-20 - poprawki wczytywania zmiennych w wersji skompilowanej z ncurses i readline jednocześnie (sz) - debug jest włączony na stałe (sz) - F12 lub Alt-` przełączają do okna z debug (sz) - debug pisze do okna o numerze 0 zamiast do statusowego (*/sz) - poprawka display_crap przy make_window == 1 (pmb/sz) - dodanie zdarzenia ,,on query'' (kameleon/w) // 2003-01-19 - poprawki kompilacji na BeOSie (w) - libgadu: poprawki kompilacji na BeOSie (w) - dodanie formatu ,,sms_conf'' przy wiadomości konferencyjnej (rmrmg/sz) - ,,on nasz_nick descr'' też zadziała (krzyk/sz) - dodanie parametru ,,*'' do del, unignore, unblock (sz) // 2003-01-18 - poprawki wyglądu ui-ncurses przy display_color 0 (w) // 2003-01-17 - make uninstall nie usuwał manuali (wysek) - poprawki /dcc get (w) - drobne sprzątanie kodu (w,sz) // 2003-01-16 - drobne poprawki dokumentacji (sz) - czasami, po zerwaniu połączenia, ekg nadal nie czyścił userlisty (sz) - kolejne drobne kroki ku unifikacji komend (sz) - nie dopełniajmy ukrytych zmiennych (sz) - dodane opcje --clear i --clear-config dla /list (fig/wysek) - dodatkowe testy przy %4 w zdarzeniach, bardziej szczegółowy opis użycia %4 w dokumentacji (jelo/w) - libgadu: poprawka konfiguracji pkgconfig (jajcus/w) // 2003-01-15 - automatyczny away zachowuje ,,tylko dla przyjaciół'' (pmb/sz) - kosmetyka themów dla /private (sz) - prawidłowe ustawianie stanu po ściągnięciu konfiguracji z serwera (sz) - poprawka ,,display_transparent'' (kotek/sz) - libgadu: dodanie nowego API do obsługi katalogu publicznego w stylu GG 5.0. przykładowe API gg_search50*() zostało zachowanie, póki co, i jest zgodne na poziomie ABI, ale będzie usunięte (Chilek/w) - update arim.theme (Arim/w) // 2003-01-14 - poprawione zachowanie zmiennych ui-ncurses przy włączonym ui-readline (kbns/w) - prowizoryczne dopełnianie nicków ze spacją w środku. działa tylko w obrębie pierwszego wyrazu (pirat/w) - kosmetyka /list, nie wyświetla własnego IP przy braku połaczenia (sz) - kosmetyka /conference, nazwa przy tworzeniu konferencji jest opcjonalna, można usuwać od razu wszystkie konferencje (sz) - poprawka możliwego segfaulta przy /timer -d * (sz) - można ignorować samego siebie. wtedy nie jesteśmy pokazywani na liście kontaktów (gozda/sz) - nowe pytanie w FAQ (sz) - ignorowanie podanego potoku przy uruchomieniu, jeśli to zwykły plik (*/sz) - poprawka opcji --private przy uruchomieniu (sz) - libgadu: poprawione wysyłanie roku urodzenia w gg_change_info() (Chilek/w) - /change nie wymaga już wszystkich parametrów (w) - /find pokazuje stan niewidoczny (gozda/w) - kolorki statusów dla /find takie same jak w /list (sz) - /find pokazuje poprawnie niektóre (private, descr) stany (sz) - poprawka zjadania 100% procesora przy -c z plikiem (*/w) - poprawka zachowania ,,make_window 1'' (rmrmg/w) // 2003-01-13 - poprawka /private (cukier/sz) - kilka mozliwych segfaultow (w/sz) - kosmetyka w msg_queue_write() (fig/sz) - segfault przy batch-mode (sz) - uaktualnienie arim.theme (Arim/w) - więcej szczegółów o F3 i zabawie z ,,contacts'' i ,,display_notify'' w dokumentacji (tokugawa/w) - poprawki themów helpa (sz/w) - poprawka usuwania /on (pmb/w) - libgadu: poprawka szukania z GG 5.0, same wnętrzności. API nietknięte (w) // 2003-01-12 - poprawka /alias (kbns/sz) - porządki kosmetyczno-funkcjonalne w kodzie timerów (sz) - pamietajmy o czyszczeniu adresu IP i portu usera tak, żeby np. w nagłówku query nie było kosmicznych adresów (sz) // 2003-01-11 - zmienna ,,display_transparent'' (MP/sz) - poprawki /on, aby było bardziej userfriendly. dodanie przekazywania nowego opisu w parametrach %3 i %4 (sz) - ,,*'' w nazwie timera i at usuwa wszystkie (ale nie timery UI) (sz) - dokładniejsze sprawdzanie argumentów w kilku funkcjach (mati/w) - poprawka dopełniania zmiennych przy włączonej liście kontaktów (*/w) - libgadu: eksperymentalny kod wyszukiwania zgodny z GG 5.0. API może się zmienić. na pewno się zmieni. trzeba uzgodnić z ekipą Kadu (w) - /find wysyła zapytania zgodne z GG 5.0 (w) - wyszukiwanie działa (w) - lekka poprawka themów wyszukiwania, ze względu na brak informacji o płci w wynikach (w) - poprawka zależności w Makefile'ach (FIG/w) - poprawka błędu autoconfa w m4/stdint.m4 (Brzezi/w) - poprawiona kompilacja przy braku openssl (boncur/w) - poprawka gg_saprintf() dla PPC (mmazur/w) // 2003-01-10 - timery (oraz at) użytkownika są zapisywane przy /save (sz) - dodanie komendy /at (sz) - zmiana timestamp'u /last i /queue na dzień-miesiąc-rok (sz) - uproszczenie kodu ,,last'' (sz) - przepisanie kodu wyświetlającego pasek stanu od nowa. można zagnieżdżać, dodano nowe formaty (w) - nagłówek okna można opisać formatami ,,header'', podobnie jak pasek stanu (w) - dodanie eksperymentalnego zamiennika sim.c. podczas testów wypada trochę lepiej niż oryginał, ze względu na brak zaawansowanych algorytmów cache'owania kluczy. po prostu za każdym razem generuje nowy. kodu jest znacznie mniej i jest bardziej przejrzysty. włączany przez ,,/set encryption 2'' (w) - poprawka zachowania kontaktów przy mieszaniu paskiem stanu i nagłówkiem (sz/w) - dodatki do pythona: można pisać w nagłówku i statusie funkcjami ekg.print_header() i ekg.print_statusbar. zdarzenie handle_keypress (w) // 2003-01-09 - dodanie komendy ukrytej _queue dla tych, którzy czasami chcą wiedzieć, co się dokładnie dzieje w kolejce wiadomości (sz) - poprawka segfaulta (cukier/sz) - libgadu: makra GG_S_*() nie zwracają uwagi na stan tylko dla znajomych (w) - libgadu: dodanie makra GG_S_F() sprawdzającego stan tylko dla znajomych (w) - libgadu: podbicie wersji API (w) - uporządkowanie kodu timerów, timeoutów itp. (w) - wyrzucenie zmiennych away i private_mode, bo tylko komplikowały sprawy (w) - różne porządki w kodzie (w) - libgadu: poprawka błędu w gg_get_line() wyjeżdżającego w pustych liniach 1 bajt przed bufor (w) - optymalizacja dodawania linii do backlogu, dzięki czemu mamy O(1) i ekg nie chodzi tym wolniej, im dłużej działa i więcej siedzi w backlogu (w) - /list na siebie pokazuje prawidłowy port (FIG/w) - poprawki configure.in (FIG/w) - możliwość rozszerzania pasku statusu zmienną ,,statusbar_size''. kolejne linie są opisane formatami ,,statusbar2'', ,,statusbar3'' itd. (w) - możliwość stworzenia nagłówka okna zmienną ,,header_size''. póki co, nie ma możliwości wyświetlania w nim czegokolwiek (w) // 2003-01-08 - poprawka ostrzeżeń przy kompilacji gcc 3.x (MuchaR/w) - kosmetyka komunikatów o błędach niektórych komend (sz) - rozszerzenie możliwości /timer (sz) - poprawka themów dla białych terminali (MP/w) - libgadu: poprawka pkgconfig (w) // 2003-01-07 - dodanie portu do /list (sz) - drobne poprawki w configure.in (w) // 2003-01-06 - drobna kosmetyka komendy /sms (sz) - poprawka timerów, które czasami potrafiły się zapętlić (fig/sz) - ,,/list user'' pokazuje też adres IP (*/sz) // 2003-01-05 - kosmetyczne poprawki przy ,,help set zmienna'' (sz) - jeśli utworzymy alias do jakiejś komendy (tylko jednej), to będzie przy nim działało dopełnianie tak, jak przy oryginalnej komendzie (sz) // 2003-01-04 - głupia ja, zepsułem ,,del'' (sz) - ładne odświeżanie listy kontaktów po ,,list --get'' (sz) - nie pozwalajmy na zmianę nazwy/uin kogoś poprzez /list, jeśli ktoś już taka nazwę/uin posiada na naszej liście (sz) - poprawka wyświetlania formatowanych wiadomości (sz/w) - dodanie formatu %|, szczegóły w docs/themes.txt (w) - dodanie ,,/help set '' (w) - instalowanie vars.txt do ${prefix}/share/ekg/ (w) - poprawki helpa /list (FIG/w) - informowanie o zapisie lub odczycie konfiguracji z serwera (FIG/w) - poprawki helpów, żeby używały %| i wyglądały ładnie po zmianie rozmiaru okna (w) - libgadu: dodanie makra GG_S_BL() (w) - libgadu: podbicie wersji API do 2.9 (w) - dokończenie kilku zapomnianych rzeczy w /list (sz/w) - eksperymentalne wprowadzenie ,,make dep''. mam nadzieję, że na egzotycznych systemach nie będzie sprawiać problemów (w) - reorganizacja timerów, dzięki czemu mają teraz odpowiednią dokładność, a nie +/- 1s. jest możliwe zrobienie stałych timerów (w) - czytanie globalnego pliku konfiguracyjnego /etc/ekg.conf, /usr/local/etc/ekg.conf itp. po konfiguracji użytkownika, żeby móc na przykład wymusić jakieś konkretne serwery (w) - dodanie opcji -N (w) // 2003-01-03 - ekg nie pozwala dodać kogoś m.in. z '@' lub '#' na początku w nazwie, żeby uniknąć dziwnych problemów (sz) - kosmetyka, m.in. rzeczy związanych z obsługa uin/nick w komendach (sz) - ignore/unignore powoduje, odpowiednio, wyczyszczenie/uaktualnienie stanu danego użytkownika. w ogóle, to trzeba będzie niedługo zrobić różne stopnie ignorowania... (sz) - poprawka wyświetlania nieznanych użytkowników w /ignore (Arim/w) - dokładniejsze informacje o błędach usług http (FIG/w) - poprawna reakcja na PageDown po /window clear (theKnight/w) // 2003-01-02 - czyszczenie stanów ludzi z listy kontaktów po timeout'cie (pmb/sz) - zmienna ,,display_pl_chars'' pozwalająca maskować polskie literki dla tych, którym nie chce się (nie mogą) skonfigurować terminala (sz) - jeśli komuś się nudzi i nadaje ludziom aliasy w postaci liczb, to nie powinien już mieć z tym problemów ;> (sz) // 2002-12-31 - poprawka ,,del'', które nie potrafiło usunąć kogoś, którego alias składał się tylko z liczby (sz) // 2002-12-30 - bardziej zrozumiałe opisy błędów przy ,,add'' (Sero/sz) - ekg nie gubi już informacji o formatowaniu wiadomości (bold, italic, etc.) podczas kolejkowania (sz) - niech systemy bez utimes() korzystają z utime() (sz) // 2002-12-29 - check_mail nie zalicza plików zaczynających się od kropki do poczty w przypadku używania Maildir/ (rmrmg/sz) - kosmetyka kodu (Sero/sz) - kosmetyka własnego IP w ,,list'' (sz) // 2002-12-27 - dodanie zdarzenia ,,new_mail'' do ,,on'' (scooty/sz) // 2002-12-26 - ekg pokazuje już, że ktoś nas ,,zablokował'' (w) - libgadu: poprawka wykrywania wersji vsnprintf(). searche, eksporty listy itp. powinny już działać poprawnie (Chilek/w) - libgadu: dodanie typów użytkowników do libgadu.h, uaktualnienie opisu protokołu (Chilek/w) - dodanie komend /block i /unblock (w) - dodanie opcji --offline i --online do /list (w) - libgadu: poprawka łączenia synchronicznego (sCoOtY/w) - usunięcie warningów przy kompilacji przykładów (w) - libgadu: gdy gg_dcc_ip będzie równe 0xffffffff, adres będzie ustalany automatycznie na podstawie getsockname() (w) - zmienna dcc_ip może przyjąć wartość ,,auto'' (w) - dodanie docs/userlista.txt z opisem formatu listy kontaktów i zapisu konfiguracji na serwerze (w) - dodanie możliwości zapisu konfiguracji ekg na serwerze (opcje --put-config i --get-config komendy /list) (w) - zmienna sms_max_length przy wartości 0 usuwa limit (rmrmg/w) - poprawka wysyłania wielolinijkowych (pmb/w) // 2002-12-24 - trochę świątecznych, głównie kosmetycznych, porządków w kodzie, m.in. pozbycie się warning'ów przy execl, które nie było ,,64 bit clean'' ;> (sz) // 2002-12-23 - przywrócenie przezroczystego tla (w) // 2002-12-22 - poprawka segfaulta przy dopełnianiu nieznanych numerów (perry/w) // 2002-12-17 - skrypty z ~/.gg/scripts/autorun/ będą ładowane automagicznie przy starcie ekg (w) // 2002-12-16 - poprawka przewijania okna (w) - poprawka ,,set -a...'' (sero/w) - zmiany w docs/FAQ - doszły nowe serwery gg (sz) // 2002-12-15 - ekg pokazuje stderr normalnie już, żeby widzieć informacje o wyjątkach pythona (w) - dodanie komendy /python (w) - początek obsługi zdarzeń w skryptach pythonowych. szczegóły w docs/python.txt (w) - poprawka /window clear (pmb/w) - poprawka /set ukrytej zmiennej (sero/w) // 2002-12-14 - kosmetyka, ,,help /komenda'' też zadziała (sz) - duża reorganizacja ui-ncurses. mogą wystąpić drobne problemy, ale starałem się przetestować wszystkie możliwe dziwne sytuacje (w) - dodanie zmiennej backlog_size, nie będzie się powiększał w nieskończoność, jak to miało miejsce poprzednio (w) - dodanie piątego parametru liczbowego do ,,/window new'', który mówi, z której strony mają być umieszczone ramki. mapa bitowa: 1 - lewo, 2 - góra, 4 - prawo, 8 - dół. wszystkie ramki to oczywiście 15 (w) - ponowne zawijanie tekstu po zmianie rozmiaru okna (chociażby przez włączenie lub wyłączenie listy kontaktów). niestety nie jest jeszcze optymalne, bo po wyświetleniu każdej linii analizuje cały bufor od nowa, ale nie chciałem zwlekać z commitem. w każdym razie, dzięki temu pływające okienka mają w końcu sens (w) // 2002-12-13 - reorganizacja sprawdzania poczty w skrzynkach mbox (sz) - poprawka segfaulta przy wielolinijkowych (seba/w) // 2002-12-11 - nie wyświetlajmy komunikatu o zakolejkowaniu wiadomości do nieprawidłowego adresata (sz) - stan ,,zajęty'' bez opisu był źle ustawiany (sz) // 2002-12-10 - poprawka segfaulta w wielolinijkowych (seba,wojboj/w) - poprawka usuwania przypisanych klawiszy (seba/w) - sprawdzanie poczty (mbox) nie przegląda niepotrzebnie całego pliku, jeśli nie było w nim zmian (sz) - poprawka śmieci w wielolinijkowych (seba/w) - działa już tab w wielolinijkowych (seba/w) // 2002-12-09 - poprawka wczytywania konfiguracji (szalik,Murphy/w) - libgadu: kosmetyka deklaracji funkcji (MatNet/w) - libgadu: usunięcie wycieku pamięci przy szukaniu (jajcus/w) - libgadu: generowanie pliku z konfiguracją systemu niezbędną do włączenia biblioteki do programu. niestety nie będzie on regenerowany przez skrypt config.status (adrians/w) - libgadu: dodanie obsługi pkgconfig. program linkujące się z libgadu mogą sprawdzać flagi kompilatora i linkera przez ,,pkgconfig libgadu --libs --cflags'' (w) - libgadu: zlikwidowanie rozbieżności ABI w wersji z i bez pthread (adrians/w) // 2002-12-08 - poprawka segfaulta przy display_crap = 0 (FIG,wojboj/w) - poprawka listy kontaktów i wielolinijkowych wiadomości (w) - poprawka segfaulta przy wielolinikowych wiadomościach (w) - komunikat o nowej poczcie zawsze zawiera słowo ,,nowe'', aby nie powodować niejasności co do tego, o jaką ilość emaili chodzi (Arim/sz) - duża ilość wywołań /exec, /sms lub sprawdzanie poczty po pewnym czasie powodowało brak wolnych deskryptorów (sz) - poprawka dokumentacji (rmrmg/w) - dodanie zmiennej contacts_descr (rmrmg/w) - dalsze zmiany pływających okienek (wojboj/w) - dodanie zmiennej windows_save (w) // 2002-12-07 - ekg potrafi już sprawdzać czy nadeszła nowa poczta, więcej w docs/vars.txt w opisie zmiennych check_mail. wymaga jeszcze optymalizacji, poprawek ;> (sz) - /bind w ui-ncurses nie dodaje sekwencji, jeśli już istnieje (sz) - porządek musi być - miejscowa kosmetyka kodu/komentarzy (sz) - compat też wymaga czyszczenia (sz) - lekkie porządki w sprawdzaniu poczty (w) - ciąg dalszy pływających okienek (wojboj/w) - poprawki dokumentacji (gophi/w) - powiadamianie o nowej poczcie na ekran (d) - powiadamianie na ekran można włączyć/wyłączyć w zmiennej check_mail (sz) - możliwość wysyłania pogrubionej czcionki (Ctrl-B), pochyłej (Ctrl-T) i podkreślonej (Ctrl-_) (w) - libgadu: dodanie funkcji gg_send_message_richtext() i gg_send_message_confer_richtext(). paskudnie to wygląda, ale ABI trzeba zachować (w) - libgadu: podbicie wersji API (w) - wyświetlanie pogrubionych, pochyłych i podkreślonych czcionek (w) - dodanie zmiennej display_color_map (w) - dodatki do zmiennej contacts (Murphy/w) // 2002-12-06 - poprawiony odczyt /bindowanych klawiszy z konfiga (kostoo/w) - dodana zmienna display_crap (Murphy,pmb/w) // 2002-12-05 - ujednolicenie nazewnictwa grup. zawsze należy używać zapisu ,,@grupa''. jedynie w miejscach, gdzie nie powoduje to dwuznaczności (list -m grupa, list alias -g grupa) dopuszczalne jest w _ostateczności_ ,,grupa'' (pmb/sz) - dodanie /bind w ui-ncurses (w) // 2002-12-04 - /list może już dodawać/usuwać z wielu grup (rodzielonych przecinkiem) na raz. dodatkowo, nie dodaje już użytkownika kilka razy do tej samej grupy. kosmetyka (sz) - po reorganizacji stanów nie zapisywał się nasz aktualny stan po /save (sz) - obsługa zdarzenia ,,blink_leds'' w ,,on'' dla solarisa (d) - mała poprawka konfliktu nazw dla solarisa (d) - dodana żałosna namiastka ,,beeps_spk'' dla solarisa (d) - --enable-ioctld już nie jest tylko Linux only (d) - kompilacja ioctld dla solarisa. powinno wystarczyć (d) - poprawia wieszającego się /exec (wojboj/w) - początek obsługi pływających okienek (wojboj/w) // 2002-12-03 - /list --member wyświetla tylko członków grupy (sz) // 2002-12-02 - uaktualnienie contrib/link.pl (theKnight/w) - poprawka reakcji na F3 (Murphy/w) - sprawdzanie, czy podany uin dla /add, /del itp. jest sensowny (sz) - /list @grupa wyświetla członków grupy (pmb/sz) - dodanie zmiennej auto_back (pmb/w) - spora reorganizacja zmiany stanu w /away, /back, /invisible, auto_away itp. więc teoretycznie mogą wystąpić problemy (w) // 2002-12-01 - kosmetyka kodu usuwania niektórych list (sz) - dalsza kosmetyka /query (sz) - błędny zapis listy nicków w chat/query wyświetli błąd zamiast utworzenia bezsensownej konferencji (sz) - usunięcie leaka przy /find (w) - libgadu: usunięcie leaka przy http (w) - drobne zmiany w ioctld (przy ,,beeps_spk'' ioctld nie potrzebuje +s) (d) - zdarzenia ,,beeps_spk'' i ,,blink_leds'' mogą działać na FreeBSD (d) - wykrywanie dla FreeBSD (d/w) - ioctld na liście wkompilowanych opcji (d/w) - porządki w autoconfie, s/true/yes/ (w) - przywrócenie /list --phone (FIG/w) - zmiana numeru w liście kontaktów usuwa stary numer (FIG/w) // 2002-11-30 - kosmetyka dokumentacji (sz) - poprawka /query, które nie potrafiło utworzyć konferencji (sz) - dodana opcja -s / --stime do ,,last'', dzięki czemu można sprawdzić, kiedy wysłana została wiadomość. przydatne, gdy nasz temat nie wyświetla timestampu wiadomości (sz) // 2002-11-29 - usunięcie opcji --phone z /find i /change (mateusza/w) - poprawka polskich krzaczków w opisie przy połączeniu (ubanus/w) - poprawka zapisywania opisu /quit przy keep_reason (w) // 2002-11-28 - mała poprawka opcji --debug w ekgsearch (wysek) - poprawka kompilacji z readline (a.latanski/w) - przeniesienie obsługi kolejki wiadomości do msgqueue.[ch] (w) - wiadomości z kolejki będą zapisywane na dysku do ~/.gg/queue po wyjściu z programu (w) // 2002-11-27 - ,,on'' może już reagować na zmianę czyjegoś opisu (rmrmg/sz) - poprawka odświeżania prompta przy activity w ui-readline (d) - /query wymaga podania prawidłego użytkownika lub numer (Murphy/w) // 2002-11-26 - dodanie zmiennej sound_notify_file (sz) - obsługa konferencji w /queue (sz) - kosmetyczne poprawki w tematach (sz) - /status nie wyświetla ilości zakolejkowanych wiadomości, gdy kolejka jest pusta (sz) - /set nie wyświetla już nieaktywnych opcji (np. log_path przy wyłączonym logowaniu, beep_notify przy wyłączonym beepaniu). żeby wyświetlić wszystkie zmienne, wpisujemy ,,/set -a'' (Arim/w) - F3 i F12 nie pokazują informacji o zmianie zmiennej (w) // 2002-11-25 - s/struct queue/struct msg_queue/, ponieważ kolidowało z SunOSowymi libcami (Murphy/w) - poprawka wykrywania scandir() (Murphy/w) // 2002-11-24 - segfault w momencie rozpoczynania konferencji (szalik/s) - kosmetyka i poprawki w last i queue (szalik/s) // 2002-11-22 - kosmetyka (szalik/w) - dodana zmienna ,,display_welcome'' (seba/w) - libgadu: wyrzucenie wielokrotnych prób czytania z socketa. jeśli nie ma danych na sockecie mimo wywołania funkcji, zrywamy połączenie, zamiast wieszać program (*/w) - poprawka dopełniania plików zaczynających się od kropki (salvador/w) // 2002-11-21 - dodanie własnej implementacji scandir(). co prawda nie działa jeszcze, ale ui-ncurses skompiluje się na SunOSach (Murphy/w) - dodanie kolejkowania wiadomości wysyłanych przy rozłączonej sesji. komenda /queue (Murphy,szalik/w) // 2002-11-20 - dodanie zmiennej ,,mesg_allow'' (mateusza,szalik/w) - poprawka leon.theme (leon/w) - inteligentne timestampy w /status (szalik/w) - literówki (szalik/w) // 2002-11-19 - poprawki ,,last'' (joshua,szalik/d) - poprawka szyfrowania (w) - poprawka segfaulta w dopełnianiu plików (salvador/w) - przezroczyste tło na kolorowych terminalach (greblus/w) - dodanie zmiennej ,,time_deviation'' (w) - usunięcie timestampów z wychodzących wiadomości (w) - inteligentne timestampy w przychodzących. jeśli wiadomość została nadana +/- time_deviation, nie wyświetla go. jeśli wysłana tego samego dnia, wyświetla tylko godzinę. jeśli wysłana wcześniej, wyświetla datę i godzinę (w) - dodany parametr ,,-d'' do /list (krzyk/w) - poprawka polskich znaków w ncurses (robson/w) - dodany format %{descr} do statusu w ncurses (FIG/w) - Alt-K w pierwszym oknie zamknie query (rmrmg/w) - libgadu: usunięcie -g z CFLAGS przy --disable-debug (adrians/w) // 2002-11-18 - poprawka reakcji F3 (kostoo/w) - libgadu: poprawka wysyłania dużych zapytań http (Chilek/w) - libgadu: nieznaczna zmiana ABI -- dodano GG_STATE_SENDING_QUERY, ale z tego względu, że jest to stała wewnętrzna biblioteki, nie podbijam ABI biblioteki (w) - libgadu: wątkowany resolver. włączany przez #define HAVE_PTHREAD lub ./configure --with-pthread (adrians/w) - kosmetyka wyglądu własnego stanu (szalik/w) - poprawki dokumentacji (mati/w) - libgadu: gg_change_passwd2() jest dostosowane do zmian w protokole (w) - dodana zmienna ,,email'' przechowująca adres e-mail użytkownia, w celu późniejszej zmiany hasła. drugi parametr nie jest już obowiązkowy w /passwd (w) // 2002-11-17 - klawisz F3 toggluje listę kontaktów (w) - tryb debugowania jest odnotowywany na pasku stanu (w) - usunięcie leaka przy debugowaniu (w) - poprawka zapisywania szyfrowanych wiadomości do /last (szalik/w) - wczytywanie z konfiga niepoprawnych zdarzeń ,,on'' jako nieaktywne (d) - poprawka polskich liter w liście kontaktów (kostoo/w) // 2002-11-16 - libgadu: poprawki w configure (adrians/w) - kosmetyka (szalik/w) - libgadu: dodanie funkcji gg_base64_encode() i gg_base64_decode() (w) - libgadu: obsługa autoryzacji proxy (adrians,leszek/w) - usunięcie leaka przy debugowaniu (w) - poprawka zawijania wiadomości przy oknie kontaktów (Zwierz/w) - uaktualnienie dokumentacji (w) - ładne, dresiarskie kolorki w liście kontaktów, zajęci (Zwierz/w) - ładne, dresiarskie ,,i'' przy ludziach z opisem (w) - poprawka zapętlenia się przy utracie terminala (Mati/w) // 2002-11-15 - ctxwindow - okienko z dostepnymi osobami (wojboj/s) - dodanie opcji --clear do ,,last'' (d) - configure nie wyrzuca informacji o interfejsie w libgadu (adrians/w) - poprawki okienka z osobami (w) // 2002-11-14 - poprawka obsługi proxy http (Chilek/w) - poprawka segfaulta przy szukaniu (*/w) - poprawka themów czasu połączenia (FIG,szalik/w) - dodanie zmiennej ,,server_save'' (*/w) // 2002-11-13 - dodany eileen.theme (en/d) - poprawki wykrywania openssl (Arim/w) // 2002-11-12 - usunięcie basename() i jego użycia (w) - dodanie nagłówków do compatowego dirname() (w) - zmiana domyślnego wyglądu statusu w ncurses. zamiast ,,uin'' jest własny nick, jeśli jest zdefiniowany w liście kontaktów (FIG/w) - dodanie serwera w docs/FAQ (szalik/w) - drobne poprawki dokumentacji (szalik/w) // 2002-11-11 - limitowanie wysyłanych sms'ów przy włączonym sms_away (szalik/s) - /status wyświetla od kiedy jesteśmy połączeni lub rozłączeni (szalik/s) - dodany leon.theme (leon/s) // 2002-11-09 - poprawka wykrywania openssl (s) // 2002-11-08 - poprawka dla "starych" systemow - libgen.h pojawilo sie dopiero w fbsd 4.2. (s) // 2002-11-06 - poprawka wykrywania na Debianach (pawsku/w) // 2002-11-05 - poprawka timestampów w logach na maszynach niezgodnych z SUS (Murphy/w) // 2002-11-03 - poprawka kompilacji na systemach bez openssl (kjtd/w) - poprawka segfaulta przy zmianie w liście kontaktów (sdas/w) // 2002-11-02 - poprawka segfaulta przy /reconnect (szalik/w) - usunięcie kodu /history (w) - przy włączonym keep_reason, stan i opis zostaną zapisane w konfiguracji bez potrzebny wydawania komendy /save (w) // 2002-11-01 - poprawka docs/themes.txt (en/w) - uaktualnienie informacji o protokole (pm/w) // 2002-10-31 - configure pokazuje, które wersje bibliotek i interfejsów zostały wybrane i które są domyślne (seba/w) - zmiana domyślnego interfejsu na ncurses. szczegóły w FAQ, w README, w tekście wyrzucanym przez ./configure (w) // 2002-10-30 - poprawka wyłączonego debugowania (Brzezi/w) - poprawka segfaultu po wygenerowaniu kluczy (FIG/w) - podanie powodu ,,-'' spowoduje jego wyczyszczenie bez względu na ustawienia jakichkolwiek zmiennych zmieniających zachowanie komend /away, /back, /invisible i /quit (w) - zmienne tekstowe są wyświetlane w cudzysłowiach (w) - dodanie skryptu contrib/ekgh (greblus/w) - poprawka wysyłania wiadomości do grup (Joshua/w) // 2002-10-29 - ze względu na duże zainteresowanie użytkowników, dodano zmienną log_timestamp (*/w) - poprawka configure.in (porridge/w) - Alt-I ignoruje rozmówcę w ui-ncurses (w) - dodanie krótkiego tekstu, który informuje, co fajnego można zrobić z okienkiem, gdy ktoś nas mesgnął (w) - poprawka timestampu w ui-readline (w) - poprawka pagera w ui-readline (Brzezi/w) - usunięcię z listy kontaktów uaktualnia nazwę okna w ui-ncurses (Perry/w) // 2002-10-28 - poprawka extract.pl (sdas/w) - dwie nowe odpowiedzi w docs/FAQ (w) - literówka w README (Brzezi/w) // 2002-10-27 - poprawki PATH_MAX dla hurd'a (s) // 2002-10-24 - dodanie komend /_keydel i /_keysend. szczegóły w docs/sim.txt (w) // 2002-10-23 - timestampy w ui-readline (Joshua/w) - wrzucenie ncursesowych promptów do głównego themu (w) // 2002-10-21 - poprawka literówki (shasta/w) // 2002-10-19 - poprawka themów wymiany kluczy (w) // 2002-10-18 - poprawienie komendy ,,last'' dla last & 2 (d) - porządki w libgadu: poprawki kodu połączenia, więcej szczegółów w debugach (na przykład adresy struktur, żeby móc wykryć operacje na niezainicjowanych wskaźnikach), znacznie więcej komentarzy do kodu (w) - poprawka linkowania z openssl (Zwierz/w) // 2002-10-17 - poprawka zapętlania się libgadu przy połączeniu zerwanym w trakcie odbierania nagłówka (w) - poprawka pagera w ui-readline (w) - /find bez parametrów działa już w ui-readline (w) - jeśli mamy zainstalowane OpenSSL, możemy używać szyfrowania SIM. szczegóły w docs/sim.txt (w) // 2002-10-16 - poprawienie wielolinijkowych wiadomości w ui-readline (d) - drobna poprawka w syntezie mowy (d) - synteza mowy w ui-readline (d) - nowe zdarzenia ,,delivered'' i ,,queued'' (Murphy/w) - poprawki opisu protokołu: długość opisu, informacje zwracane przez huba (adaml/w) // 2002-10-15 - dodanie syntezy mowy, szczegóły w README. uprzedzając pytania, działa tylko w ncurses. (tarapat/w) // 2002-10-13 - poprawka aliasów z ,,/'' (mateusza/w) // 2002-10-10 - poprawienie segfaulta przy /disconnect z opisem (w) // 2002-10-09 - pokazuje opis przy połączeniu (theKnight/w) // 2002-10-08 - poprawka konferencji (DJ/w) - poprawka ,,-c'' w getopt (serek/w) // 2002-10-07 - poprawka płci w wyszukiwaniu (FIG/w) // 2002-10-06 - poprawka logowania w iso (wielu/w) - poprawka synchronicznych połączeń (hao/w) - dodanie kolejnego ui-automaton przeznaczonego do współpracy z pluginem do irssi (malekith/w) - poprawka własnego adresu w liście kontaktów (FIG/w) // 2002-10-05 - /query z drugim parametrem wysyła od razu wiadomość (czach/w) // 2002-10-04 - usunięcie #include "db.h" (a.latanski/w) - nieco inteligentniejsze ioctld_socket() (d) // 2002-10-03 - s/csae/case/ przy WITH_IOCTLD (d) - wyświetlanie wyniku wysyłania smsów (wojboj/w) - poprawki konferencji, wyświetlanie jej nazwy (DJ/w) - wyrzucenie -I/usr/include z flag kompilatora (malekith/w) - poprawka kodu o niezdefiniowanym działaniu (malekith/w) - porządki z ui_event() (malekith/w) - porządki w configure.in i Makefile.in (w) - proste dopełnianie plików w ui-ncurses (DJ/w) - poprawka wyświetlanie własnego stanu niewidocznego (w) - dodanie użytkownika powoduje uaktualnienie nazwy okienka (w) - po wielu latach w końcu saprintf() nie zwraca NULL (w) // 2002-10-02 - wyświetla potwierdzenia w oknie rozmowy (theKnight/w) - o zbyt długim opisie informacja poprawna gramatycznie bardziej (konik/w) - /find szuka rozmówcy albo nas samych. dotyczy ui-ncurses (w) - usunięcie niedokończonego 2k2.theme (w) - usunięcie timestampów z domyślnego themu. stary został zachowany w old.theme (w) - domyślne włączenie timestamp "%H%M " (w) - uaktualnianie własnego stanu w liście kontaktów (w) - przejście na getopt() (DJ/w) - dodanie katalogu compat/, na wypadek, gdyby systemowi brakowało funkcji getopt_long (w) // 2002-10-01 - round robin serwerów (w) - wiadomość (nie mylić z rozmową) nie otwiera nowego okna (theKnight/w) // 2002-09-30 - poprawka usług http. możliwe, że znajdą się jakieś błędy, bo nie byłem w stanie sprawdzić tego w każdej możliwej konfiguracji (wiele_osób/w) - poprawka debugowania (nie blokuje już rurki, co doprowadzało do wieszania się ekg przy dużej ilości debugowych tekstów) (w) - dodanie zmiennej enter_scrolls (jp/w) // 2002-09-28 - poprawka sms_away i back z opisem (kbns/w) // 2002-09-25 - dalsza rewolucja w krainie autoconf/python (s) // 2002-09-24 - kolejne poprawki /exec (wojboj/w) - dodanie string_clear() (w) - poprawki debugowania (sdas/w) - mały cleanup w ekgsearch (wysek) - jeśli pubdir jest przeciążony, ekgsearch napisze o tym (w/wysek) - drobne poprawki w docach (w) - optymalizacja /exec (w) // 2002-09-23 - optymalizacja string_*() (wojboj/w) - poprawka /exec (wojboj/w) - dodanie konferencji do dopełniania (DJ/w) - poprawka configure.in/LDFLAGS (s) - /msg do wielu osób nie tworzy konferencji (joshua/w) - rewolucja w krainie autoconfa (s,w) - informacje o rozpoznawaniu płci w dokumentacji (w) - poprawka segfaulta przy quicie (s/w) - poprawka głupiego zachowania readline (Zwierz/w) - dodanie debugów do ui-ncurses (w) - usunięcie leaka przy /set (w) // 2002-09-22 - poprawki /exec (wojboj/w) - poprawki wyszukiwania -- dokładniejsze komunikaty błędów (w) - zwiększenie limitu rozmiaru opisu (jojo/w) - przy zmianie stanu, zaznaczana jest widoczna i ucinana część opisu (jojo/w) // 2002-09-21 - poprawka themów ze stylami (Arim/w) - poprawka execa z ukrytym zakończeniem (sdas/w) - dodanie pól gg_dcc->remote_{addr,port}, podbicie wersji API (w) - błędy dcc informują również o adresie IP, żeby wiedzieć kto nas może DoSować (w) - poprawione wysyłanie mesgów do nieistniejących (jojo/w) - poprawka rozpoznawania płci w /list (w) - poprawka informacji o użytkownikach (sdas/w) - dodanie stałej GG_STATUS_DESCR_MAXSIZE (jojo/w) - informowanie o przekroczeniu rozmiaru opisu (jojo/w) - libgadu potrafi ustawiać opis przy logowaniu (w) - ekg zachowuje opis przy /save (FIG/w) - poprawki w /help (FIG/w) - możliwość usuwania użytkowników (DJ/w) - poprawione /exec (wojboj/w) - poprawka głupiego zachowania ui-ncurses przy pustych liniach (sdas/w) // 2002-09-20 - poprawka statusbara (sdas/w) - /find bez parametrów szuka nas samych (sdas/w) - puste linie nie są zapisywane w historii (sdas/w) - usunięcie leaka w add_send_nick() (w) - usunięcie leaka w ui-ncurses (w) - uconstowienie command_exec() i argumentów komend (w) - poprawka segfaulta przy nieudanym szukaniu (wojboj/w) - ustawianie LDFLAGS w configure.in (sdad,wojboj/w) - pominięcie /usr/include/readline.h w wykrywaniu readline, żeby nie powodować błędów na NetBSD. wszystkie w miarę nowe wersje readline instalują się w $prefix/include/readline/readline.h (w) - wysłanie wiadomości nie otwiera okienka (jojo/w) - poprawka helpa aliasów i debugowych komend (sdas/w) - przerzucenie tekstu z F1 do theme'u (thv/w) // 2002-09-19 - poprawki dopełnień w ui-ncurses (theKnight/w) - zmiany stanu zawsze wrzuca do pierwszego okna (theKnight/w) - wskaźnik (more) w ui-ncurses (sdas/w) - ładowanie themu zeruje poprzedni (Arim/w) - początek obsługi xtermowych tytułów (jojo/w) - dodana zmienna keep_reason (jojo/w) - format statusbara %{nick} i %{?nick ...} (FIG/w) - ładniejszy /status (FIG/w) - poprawka /set i nieistniejących zmiennych (sdas/w) // 2002-09-18 - poprawka segfaultu przy sortowaniu okien w ui-readline (wojboj/w) - ignore/unignore akceptują konferencje (DJ/w) - update DJ.theme (DJ/w) - poprawka długich linii w ui-readline (*/w) // 2002-09-17 - literówka w themie (thv/w) - osobny format dla timestampów wysyłanych mesgów (FIG/w) - update themów (Arim/w) - themy mogą mieć kilka dostępnych wyglądów. rodzaj wyglądu podaje się po przecinku za nazwą pliku. przykład ,,set theme arim'' i ,,set theme arim,irc''. różne wyglądy definiuje się przez dodanie do themu wpisów z nazwami zakończonymi przecinkiem i nazwą. póki co, eksperymentalne -- sposób zapisu i określania może się zmienić. (Arim/w) - poprawka /query (Arim/w) - dodanie /conference --ignore, --unignore i --find (DJ/w) // 2002-09-14 - poprawka segfaultu w /set (mihau/w) - poprawka dokumentacji docs/on.txt (thv/w) // 2002-09-13 - sent_line* zawierają datę wysłania mesga, a nie 1.01.1970r (Arim/w) - update dj.theme (DJ/w) - możliwość zmiany nazwy konferencji (DJ/w) - poprawka błędu przy log_status 1 (speedy/w) - naprawienie zmiennej timestamp w ncurses (czach/w) - ,,W pogoni za kursorem'' (DJ,czach/w) // 2002-09-12 - completion_notify ma nową flagę 4 (busy), która bierze pod uwagę również zajętych (Murphy,kameleon/w) - ,,window clear'' działa w ui-ncurses. wzorowane na irssi, gdzie zawartość okna nie jest kompletnie czyszczona, tylko przewijana poza obszar ekranu (w) - zmiana zachowania gg_search(). active w wyniku będzie zawierało stan danej osoby. z tego względu będzie wyświetlało też zajętych jako dostępnych w aplikacjach. podbicie API, mimo że powinno być ABI. tyle, że z powodu takiej bzdury nie warto psuć zależności (w) - wielolinijkowe wiadomości w ui-ncurses, wywoływane Ctrl-Enter, Alt-Enter lub Esc-Enter. wysyłane tą samą kombinacją, anulowane samym Esc. teoretycznie może powodować segfaulty, ale sprawdziłem valgrindem i niczego niebezpiecznego nie znalazł. (w) - konferencje. wynalazek ten obsługuje się poleceniem ,,conference''. okienka będa automagicznie tworzone, jeśli mamy odpowiednie ustawienia. (dawjar/w) - zmiana kolejności poszukiwania themeów (dawjar/w) - update dj.theme (dawjar/w) - dodanie GG_STATUS_BLOCKED (Chilek/w) - dodanie funkcji gg_notify_ex(), gg_add_notify_ex() i gg_remove_notify_ex(). podbicie API (Chilek/w) - ujemna wartość formatów _line_width powoduje odjęcie ich od szerokości ekranu (czach/w) - naprawienie rozrzucania mesgów po okienkach, zepsutego jednym z patchy (w) // 2002-09-11 - dodany skrót "-A" dla parametru "--all" w ekgsearch (wysek) - komenda set akceptuje i wyświetla flagi dla niektórych zmiennych. możliwe jest dodawanie flag poprzedzając wartość plusem, lub usuwanie poprzedzając minusem. na przykład ,,set log +gzip'' lub ,,set random_reason -away'' (w) - porządki w configure.in. nie wykrywamy niepotrzebnych rzeczy -- na przykład jeśli nie znajdzie libgsm, nie sprawdza ; jeśli nie chcemy ioctld, nie szuka (w) - obsługa logów skompresowanych gzipem: ,,set log +gzip''. jeśli dany log już istnieje, będzie dopisywany w postaci nieskompresowanej -- należy go najpierw skompresować ręcznie za pomocą komendy gzip (w) - uaktualnienia, dodatki i poprawki w dokumentacji (w) - usunięcie configure z cvsu. będzie generowany automagicznie przy tworzeniu snapshotów (speedy/w) - jeśli podczas ./configure-owania będzie w katalogu plik .enable-ui-ncurses, to zostanie wkompilowane. mam dość zapominania o tej opcji (w) - regeneracja configure po zmianach configure.in, m4/* i acheader.h (w) - poprawka błędu przy usuwaniu zmiennych (speedy/w) - tab completion przy ,,window'' (jr178783/d) - poprawka rzucania wiadomości do innych okienek. tak, przyznaję, moja wina. głupi błąd. (w) - matik.theme (matik/s) - ,,find -A'' wyświetla wszystkie wyniki (wysek/w) - wynik wyszukiwania nie jest już rozstrzelony co dwie linijki (w) - dodanie gg_search_request_free(), podbicie API (w) - dodanie osobnych timestampów dla czasu nadania wiadomości (Bies/w) - poprawka potencjalnego segfaulta w szukaniu (wysek/w) - poprawka czasu wiadomości w ekgwap (serek/w) // 2002-09-10 - inna filozofia gg_saprintf(). rodzaj maszyny (pre-C99 lub post-C99) jest wykrywany przez ./configure. dodatkowo zmieniono lekko sposób uzyskiwania rozmiaru na post-C99, żeby działało poprawnie na Sunach (Murphy/w) - segfault przy completion_notify 2 i dopełnianiu tabem (Murphy/w) - usunięcie niepotrzebnego już katalogu misc/ (w) - dodanie arim_irc.theme, dj.theme (Arim,dawjar/w) - usunięcie niepotrzebnych includów z libgadu (m.in. ) (w) // 2002-09-08 - mamo, a speedy popsul VOIP i ncurses ;P (s) - wymuszanie ui-readline [--enable-force-readline] (s) - sigh... dlaczego config.h.in sie nie robilo ? (s) - poprawka dopełniania tabem (jp/w) // 2002-09-07 - dodane komendy ,,last'' oraz zmiennej ,,last_count'' (d) - update ,,docs/vars.txt'' (d) - dodanie zmiennej ,,last'' (d) - zmiana ,,last_count'' na ,,last_size'' (d) - uaktualniony ,,docs/vars.txt'' (d) - dodany ,,last_list_timestamp'' do themes (d) - poprawne zapisywanie polskich znaków mesgów wychodzących w last (d) - s/get_last_count/last_count_get/ (d) - brakujące sent_line_first (dawjar/w) - usunięcie kilku drobnych leaków (w) - ekg pyta się o zapisanie konfiguracji, nie ui (Arim/w) - Ctrl-Fx zmienia okno na konsoli FreeBSD (cukier/w) // 2002-09-06 - update arim.theme (Arim/w) - ui-readline respektuje zmienną ,,sort_windows'' (d) - ui-ncurses poprawnie wykrywa płeć przy imionach z polskimi znakami. widocznie ncurses coś psuje (Arim/w) - prompt z nickiem query w ui-ncurses (w) // 2002-09-05 - ui-ncurses respektuje zmienną display_color (w) - informowanie o zmianach w oknach w ui-readline (d) - dodanie zmiennej display_sent (w) - zniesienie ograniczeń rozmiaru ekranu. póki co, jeszcze nie będzie się dostosowywał do zmian rozmiaru terminala (w) - mniejsze poprawki ui-ncurses (w) - dodanie ,,window next'' i ,,window prev'' (w) - obsługa Ctrl-L w ui-ncurses (Kooba/w) - w query domyślne dopełnianie dodaje '/' (jojo/w) - dodanie zmiennej sort_windows (wielu/w) // 2002-09-04 - ładniejszy, dresiarski status w ui-ncurses (w) - ładniejsze, dresiarskie prompty w ui-ncurses (w) - początek timestampów _przed_ linią (w) - ui-ncurses obsługuje Ctrl-W (w) - obsługa okienek w ui-ncurses. jest jeszcze niekompletna w stosunku do okienek z ui-readline, ale ma też sporo zalet -- dresiarski status i informowanie o zmianach w oknach. szczegóły w docs/ui-ncurses.txt (w) // 2002-09-03 - dodanie ' do znaków escapowanych w logach, żeby można było łatwo i przyjemnie to rozbić przez array_make(), która już obsługuje escapowane teksty (w) - poprawki w helpie (w) - nie można utworzyć aliasu przykrywającego komendę (FIG/w) - dodanie zmiennej save_password (FIG/w) - dodanie argumentów do connect (FIG/w) - polecenia przy braku parametrów proponują zajrzeć do pomocy (FIG/w) - pseudokonfigurowalny statusbar w ui-ncurses, szczegóły w źródłach. póki co, pokazuje zegarek, numerek i kolorem określa stan (w) // 2002-09-02 - pager w bind (FIG/w) - segfault przy dcc (theKnight,wojboj/w) - escapowanie logów (w) // 2002-09-01 - z okazji urlopu dodalem eksperymentalne wykrywanie pythona (s) - poprawka kolejności includów (kloczek,Charvel/w) // 2002-08-25 - dodanie funkcji gg_libgadu_version() zwracającej wersję biblioteki i makro GG_LIBGADU_VERSION, które podaje wersję inkludów (w) - ekg -v zwraca wersję ekg i libgadu ze szczegółami (niepamiętamkto/w) - podbicie wersji api (w) - poprawki voip (Chilek/w) - MILI PAŃSTWO, PROSZĘ PRZYGOTOWAĆ SZAMPANA! pierwszy snapshot, który znalazłem na dysku to 20010825 ---- wynika z tego, że minął rok od pierwszej zachowanej, nieoficjalnej wersji ekg. jeśli ktoś chce się pośmiać, zapraszam do http://dev.null.pl/ekg/stare/ekg-2001082501.tar.gz a jako ciekawostkę załączam wykres rozmiaru tarballa w czasie (jest pod adresem http://dev.null.pl/ekg/tarball.png). dziękuję za uwagę i przepraszam za zaśmiecanie changeloga. (w) // 2002-08-23 - \n po zamknięciu query (theKnight/w) - dodanie zmiennej ctrld_quits (rmrmg/w) - dodanie contrib/link.pl (theKnight/w) // 2002-08-22 - msg @grupa wysyła do wszystkich członków grupy. żeby wysłać do kogoś, czyj nick zaczyna się od małpy, należy wpisać msg ,@nick (zdzichuBG/w) // 2002-08-21 - usunięcie innego aliasu w aliasie nie wywala klienta (theKnight/w) - bind bez parametrów pokazuje listę (theKnight/w) // 2002-08-20 - początek obsługi skryptów Pythona. jak większość ficzerów, w stanie używalnym będzie dopiero za pół roku. szczegóły w docs/python.txt (w) - dodane timery, które przydadzą się w skryptach. do tego można nimi zarządzać komendą ,,timer'' (w) - dalsze psucie pythona. dodanie przykładowego skryptu. dodanie komendy _py, która wykona kod w pythonie (w) - usunięcie copyrightów z docs/README i z bannera, żeby wymienieni ludzie nie byli traktowani jako jedyni autorzy (w) - sensowne opisanie instalacji w docs/README (w) - komenda quit jest już traktowana jako zwykła komenda, przez co nie powinno być problemów z aliasami i timerami. niestety spowoduje to leaki pamięci przy wychodzeniu, ale tym zajmę się kiedy indziej (w) - reorganizacja skryptów pythona. nie działają. (w) // 2002-08-19 - poprawka kolejnej konstrukcji mogącej powodować segfaulty. niech żyje readline! (w) - poprawka błędu w rozwijaniu emotikonów (theKnight/w) - wysyłanie rozmów grupowych (stforek/w) - wyraźne zaznaczenie wersji licencji (L)GPL (w) - poprawka wyświetlania mesgów w ui-readline (dawjar/w) // 2002-08-18 - głupie porządki w kodzie. mniejszenie ilości #ifdef WITH_IOCTLD, zmiany nazw funkcji dotyczących ioctld itd. (w) - pozbycie się głupiego błędu z czyszczeniem ekranu po włączeniu ekg (w) - wyłączenie domyślnej kompilacji ioctld. czasami jest z tym jednak więcej kłopotów niż pożytku (w) - segfault w _msg (w) - możliwość robienia theme'ów ircopodobnych. przykład w themes/irc.theme (w) - jest już dopełnianie tabem w ui-ncurses. niniejszym ogłaszam ten interfejs używalnym. jak zwykle, prosimy zapiąć pasy, spodziewamy się nieznacznych turbulencji (w) - poprawka ui-readline, by uniknąć potencjalnego segfaulta (adwol/w) - segfault przy podwójnym bindowanie (booyas/w) // 2002-08-15 - poprawki współpracy z ekgwap (serek/w) - porządki w theme'ach. błędy połączenia będą już zawsze pokazywane po polsku i będą mówiły co naprawdę się stało. precz z errno! (w) - polecenie bind obsługuje już klawisze z altem (w) // 2002-08-13 - niedostępni będą dopełniani tabem przy completion_notify=2 (Joshua/w) // 2002-08-12 - lista funkcji w docs/api/ref.html (w) - dodanie informacji do help bind (Murphy/w) - poprawienie kilku themeów (w) - poprawki w okienkach (w) - poprawka segfaultu w status (FIG/w) - poprawka --enable-wap (serek/w) - nowa zmienna ,,tab_command'' (Murphy/w) - niedostępni nie będą dopełniani tabem (Murphy/w) - poprawka NAPRAWDE IDIOTYCZNEGO błędu. powinienem sobie chyba darować to wszystko. wszystkie operacja na listach alokowały za mało pamięci. (w) // 2002-08-11 - czas nadania wiadomości w UTC (alfapawel/w) - literówki (FIG/w) - przygotowanie kodu pod ekgwap. rozwój jest prowadzony gdzie indziej (http://www.comm.pl/~serek/ekgwap/), ale po co za każdym razem dostosowywać patche do aktualnej wersji ekg? (w) // 2002-08-10 - poprawka lib/http.c dla przypadku, gdy nagłówek przychodzi osobno z danymi (wojboj/w) // 2002-08-09 - poprawka themeów kolejny raz (joshua/w) - uaktualnienie protocol.html (kdebski/w) // 2002-08-07 - poprawka standardowego theme + nowy przelacznik (zaor/s) - poprawka bezpośredniego połączenia z serwerem dla synchronicznych (hao/w) - poprawka wywołań gg_free_event (w) - dodanie win32, szczegóły w README (hao/w) - rozszerzenie komend /version i /status (FIG/w) - poprawka ^D w pagerze (FIG/w) - dodanie komentarzy i \$Id\$ w win32/*.h (speedy/w) - speedy mnie zabije za zepsucie /status. poprawione (w) - naprawienie odbioru dcc. nagłówek chunka może być już podzielony na dwa pakiety. po tylu latach. przepraszam. (Chilek/w) - Traalala.. mozecie bic, ale na bialym tle biale literki zle wygladaja ;> zaor zwrocil uwage i stwierdzil ze pogrubione znaczy tluste jest lepsze (s) - rewrite dużej części kodu okienek. już wolę posiedzieć, zrozumieć co robi która funkcja, niż czytać codziennie na ekg-users kolejne porcje core'ów. przy okazji Ctrl-D w okienku zamyka je. (w) - informacja o ulotce jest już wyświetlana w /help (FIG/w) // 2002-08-06 - poprawki libgadu pod kątem kompilacji pod win32 (hao/w) - malutki porządek w ui-readline (w) - poprawka segfaulta w ui-readline przy usuwaniu okienek (goblin/w) - ignorowanie autom4te.cache z autoconfa 2.53 (w) - zapomniany patch na wrzucanie ioctld do libexecdir (porridge/w) - s/struct list \*/list_t / (w) - s/AUTHOR/AUTOR/ w docs/ekgsearch.man.pl (w) - sunowe libce chyba nie akceptują NULL w %s, naprawiono (speedy/w) - dodana zmienna ekg_segv_handler, która mówi funkcjom ui_deinit(), żeby niczego nie zwalniały, bo może być jeszcze gorzej (w) - s/windows_sort/window_sort/ w ui-readline (w) - poprawienie potencjalnego błędu w ui-readline (w) - literówki w komentarzach (w) - docs/api z prostym skryptem generującym dokumentację (w) - zamiana ,,unsigned long'' na ,,uint32_t'' i ,,unsigned short'' na ,,uint16_t'' w libgadu (w) - podbicie wersji ABI. na maszynach, gdzie nie ma wyrównywania do 4 bajtów mogą być problemy z okazji zmian rozmiarów zmiennych (w) - s/gg_free_event/gg_event_free/ plus #define dla kompatybilności wstecz (w) - s/gg_free_search/gg_search_free/ (w) // 2002-08-05 - aliasy naprawione. są już traktowane na równi z komendami, więc nie powinno być sytuacji, gdy komendy działają, aliasy nie (w) - poprawione formatowanie (rmrmg/w) - poprawiony błąd w gg_saprintf() (hao/w) // 2002-08-04 - s/ekg_execute/command_exec/ (w) - komendy są już w liście, nie w tablicy (w) - aliasy nie działają (w) - zapomniane podbicie ABI (arekm/w) // 2002-08-03 - poprawka opisów funkcji w źródłach. pora zabrać się za automagiczne generowanie opisu api (w) - zamiana fix16 i fix32 na gg_fix16 i gg_fix32. nie może być tak, że libgadu.{so,a} eksportuje nazwy niepoprzedzone prefiksem gg_. dla zachowania kompatybilności tworzy aliasy, ale zostaną one usunięte w przyszłości. (w) - poprawka pubdir.c (hao/w) - zamiana arytmetyki (void*) na odpowiednie typy, ponieważ niektóre kompilatory nie pozwalają dodawać (void*)'ów (hao/w) - przepisanie handle_status() od zera. mniej kodu, mniej błędów (w) - poprawka extract.pl (Arim/w) - poprawka gg_logout (hao/w) // 2002-08-02 - valgrind jest *PRZEPIEKNY*, na dzisiaj dwa leaki usunięte (w) - naprawienie va_format_string() -- nie sięga w va_list głębiej niż jest to potrzebne. valgrind mniej śmieci (w) - zwalnianie wszystkiego, co nie jest potrzebne ekg. tak, trochę się to różni od dotychczasowej polityki (po co zwalniać, skoro i tak exit() się tym zajmie), ale w ten sposób znacznie łatwiej jest wykrywać leaki (w) - zwalnianie w ui-readline (w) - poprawka off-by-one w ui-readline z MAX_LINES_PER_SCREEN (w) // 2002-08-01 - literówki w dokumentacji (Gophi/w) - brakujące (DomBal/w) // 2002-07-27 - możliwość nieuruchamiania ./configure przez ./autogen.sh (porridge/w) - AC_PREREQ (porridge/w) - ekg może być linkowane dynamicznie z libgadu (porridge/w) - many dla ekgsearch (porridge/w) - literówki (porridge/w) - ioctld nie jest instalowany z suidem (w) - instalacja manów ekgsearch (w) - dużo psucia autoconfów i Makefile'i (w) - dodanie ,,make uninstall'', które usuwa pozostałości po różnych wersjach i konfiguracjach ekg (w) - wersja statyczna libgadu jest kompilowana bez -fPIC, dzielona z -fPIC, przez co w najgorszym wypadku będzie kompilowana dwa razy (porridge/w) - konwersja cp->iso userlisty z serwera (a.latanski/w), - zamiana spacji na podkreślenia w userliście z serwera (a.latanski/w), - ,,display_notify 2'', szczegóły w docs/vars.txt (w), - dodanie prostych hashy themeów i zmiennych, żeby ltrace nie zaśmiecało konsoli przez 5 minut przy starcie programu. przy okazji ekg będzie startowało około 20us szybciej (w), - s/struct list */list_t /, s/struct string */string_t / (w) - drobne porządki w kodzie ekg (w) // 2002-07-25 - jeśli wykryje , robi --with-ioctld (w) // 2002-07-24 - poprawki configure dla Murphy'ego (w) // 2002-07-23 - dodanie obsługi znaków ĄąŚśŹź w ekgsearch (wysek) - poprawka komunikatu przy segfaultach (w) // 2002-07-22 - dodanie komendy ,,bind'' (d) - dopisywanie do konfiga bindowanych klawiszy (d) - drobne zmiany w ,,bind'' (d) - dalsze poprawki (d) - uaktualnienie ,,docs/FAQ'' (d) - lekkie poprawki obsługi eventów (w) - poprawka wykrywania ncurses (w) - poprawka gg_send_message_confer (Chilek/w) // 2002-07-21 - poprawka komendy ,,alias'' (eileen/d) // 2002-07-20 - porządki w poleceniu help (w) - dodanie komendy echo (w) - dodanie akcji zdarzeń ,,exec'' (w) - poprawka zdarzeń z wieloma akcjami (w) - dodanie %4 w zdarzeniach, które zawiera eskejpowaną treść wiadomości (w) - poprawki dokumentacji. dodanie gdb.txt, przenosny-kod.txt (w) // 2002-07-19 - poprawki dokumentacji (tommy/w) - update arim.theme (arim/w) - poprawka DESTDIR (baseciq/w) - omijanie braku FIONBIO fcntlem (adwol/w) - poprawka pagera, o jedną linię za mało (neeo/w) - spacja nie wywołuje aliasu (perry/w) - kod obsługi konferencji (Chilek/w) - podbicie libgadu.so.0.10 (w) // 2002-07-18 - poprawienie wyświetlanie długich promptów przy alt+? (arim/d) - ,,window refresh'' po ,,window clear'' (d) // 2002-07-15 - wywalenie printfa (neeo/w) // 2002-07-12 - przepisanie curses.m4 od zera unikając wielokrotnego wywoływania makr. dzięki temu configure zajmuje ~100kB mniej (w) - dodanie $(DESTDIR) do Makefile (jajcus/w) - instalacja libgadu.h, polskich manów, ekgsearch (w) - przepisanie readline.m4 od zera. teraz się zacznie narzekanie na mnie na ekg-users (w) - dodanie opcji --all i --debug, usunięcie opcji --raw w ekgsearch (wysek) - poprawka dość nieciekawego segfaulta (print() przed ui_init()) (baseciq/w) // 2002-07-11 - poprawka aliasów w query (theKnight/w) - poprawka Makefile dla --with-shared (Charvel/w) - dodanie skryptu ekgsearch (wysek/w) // 2002-07-10 - poprawki w numeracji libgadu.so, szczegóły w lib/Makefile.in (jajcus/w) // 2002-07-08 - dodana komenda ,,window list'' (d) - dodana zmienna ,,make_window'' (d) - update ,,docs/vars.txt'' (d) - poprawka odświeżania prompta w okienkach (d) - poprawka obcinania chat_headera (arim/d) - poprawka ,,query_finished'' z themes.c (d) - s/Okienku/Okienko/g w themes.c (grzelo/d) - dodanie docs/emoticons.ansi (mateusza/w) // 2002-07-07 - update sic.theme (sic/w) // 2002-07-06 - sprawdzanie czy query istnieje (d) - poprawka gg_dcc_debug_data (Chilek/w) - błąd w GG_CLASS_ACK (acc/w) // 2002-07-05 - poprawiony segfault w okienkach (d) - lekko zmodyfikowane funkcje window_0X (d) - drobna poprawka odświeżania przy ,,window_switch()'' (d) - poprawka segfaulta przy away/back/... (rmrmg/w) - poprawka INADDR_NONE (Murphy/w) - obsługa forwardowania portów. dodatkowe pola gg_login_params: external_addr, external_port (Chilek/w) // 2002-07-04 - update arim.theme (arim/w) - update opisu protokołu: GG_CLASS_ACK (acc/w) - update opisu protokołu: GG_LOGIN_EXT (pm,ajron/w) - poprawka beepania w ui-readline (ghunt/w) - dodanie lib/compat.h, który będzie zawierał wszystkie dziwne deklaracje dla dziwnych systemów (s/w) - dodanie makra GG_PACKED, które przydaje się przy definicji struktur (w) - dodane okienka do ui-readline (d) - mały cleanup (w) - poprawka kombinacji alt+[1-9] (d) // 2002-07-03 - początek ui_event() (w) - poprawiony segfault w ,,dcc get #'' (Chilek/w) - update feeg.theme (feeg/w) // 2002-07-02 - usunięto problem z select()em przy wychodzeniu (ekg-users/w) - dostępny z opisem idzie do dopełnienia już (joshua/w) - dodane docs/http.txt (pm/w) // 2002-06-29 - poprawka includów dla FreeBSD (argasek/w) - poprawka edycji linii w ui-ncurses (w) - poprawka dcc (Chilek/w) - poprawka ui-readline (seba/w) // 2002-06-28 - porządkowanie funkcji w stuff.c (w) - dodawanie const do deklaracji funkcji, gdzie trzeba (w) - porządki w event_flags() i event_format() (w) - historia i edycja linii w ui-ncurses. jest już używalne. (w) // 2002-06-27 - wydzielenie kodu readline. bardzo możliwe, że przy okazji coś zostało zepsute. w razie problemów krzyczeć (w) - przygotowanie do tworzenia innych frontendów, szczegóły w docs/ui.txt (w) - poprawka aliasów (MG/w) - dodałem parametry --enable-ui-*. oczywiście nie działają. (w) - dodanie ui-batch, który nic nie robi dla trybu wsadowego. (w) - początek ui-ncurses. na upartego da się tego już używać. (w) - porządki w configure.in (w) - namiastka tab completion w ui-ncurses (w) - parametr -f do wyboru ui (w) - dodanie ui-none (w) // 2002-06-25 - poprawka segfaulta z -t (qbas/w) // 2002-06-22 - poprawka aliasów (perry/w) - poprawka devel-hints.txt (w) - dodanie xmalloc.[ch], zmiana wszystkich alokacji w ekg na funkcje x*(). niestety libgadu nie może być zależne od tego, więc tam nadal będzie zabawa w sprawdzanie wszystkiego (w) - uaktualnienie helpów /back i /invisible (gophi/w) // 2002-06-21 - aliasy mogą już wywoływać quit (ekg-users/w) - pusta linia nie wywołuje aliasów (joshua/w) - poprawka klith.theme (MG/w) - testowy commit (w) // 2002-06-19 - mała proteza dla themeów które zmieniają aliases_add (arim/w) - usunięto --wait (charvel/w) // 2002-06-19 - poprawki libgadu, żeby ignorować przynęty (w) - poprawka reakcji na ctcp (w) - /status podaje adres serwera (seba/w) - poprawka /set (seba/w) - wielokomendowe aliasy. kolejną komendę dodaje się przez ,,alias -A'' (w) - poprawka charsetu logów (joshua/w) // 2002-06-18 - drobne poprawki dcc (ekg-users/w) - zmiana adresu huba z appmsg.asp na appmsg2.asp. możliwe, że pomoże to na problemy z zabronionym dostępem (w) - wyłączenie /history. na litość boską, jak jeszcze raz zobaczę taki kod to zabiję ;/ (w) // 2002-06-17 - history command (tri10o/s) - need cleaning... but now works ;> // 2002-06-16 - poprawki głosowych (s/w) - poprawka kolejności argumentów linkera. pomoże sunosom, innym nie zaszkodzi (Beeth/w) - poprawka auto_reconnect (Yarko/w) // 2002-06-15 - s/u_int/uint/, brakujące #include "config.h" (Beeth/w) - dodany opis docs/voip.txt, uaktualnienie FAQ (w) - dodane włącz/wyłącz debug pod F12. nie będę się bawił w obsługę wszystkich terminali. jak komuś potrzebny inny, to niech podeśle patcha (w) - poprawki configure.in (w - poprawka błędów przy --without-debug (cooler/w) - dalsze poprawki configure.in (w) - poprawki rozmów głosowych (w) // 2002-06-14 - mocna przebudowa kodu dcc. makra gg_read() i gg_write() odchudziły nieco kod i zwiększyły odporność na błędy sieci. przygotowanie pod rozmowy głosowe. (w) - zmiana API, dodane zdarzenie GG_EVENT_DCC_CALLBACK, po którym należy wywołać gg_dcc_set_type() (w) - dodane i -lgsm, jeśli są w systemie. teoretycznie obsługuje rozmowy głosowe, ale nie testowano dobrze. (w) - dodanie ,,dcc close #x'', które przydaje się w głosowych (w) // 2002-06-13 - s/init_pipe/init_control_pipe/ w stuff.h (d) - wywalenie warninga przy ,,changed_dcc'' (d) - dodana zmienna ,,dcc_dir'' (d) - update docs/vars.txt (d) - poprawka quita (chilek/w) // 2002-06-12 - poprawka quita (carnil/w) - wszystkie kombinacje dcc działają, tadaaaa! (w) - update dokumentacji (w) - poprawka wysyłania dcc (chilek/w) // 2002-06-11 - duże poprawki configure.in, */Makefile.in, przygotowujące pod osobną dystrybucję libgadu (w) - drobne poprawki dcc (w) - dodanie -Wall (w) - ,,dcc send 12345 plik --reverse'' wysyła pasywnie bez względu na to czy klient jest za maskaradą czy nie (w) // 2002-06-10 - poprawki dcc, dodanie gg_dcc_get_file() (chilek/w) // 2002-06-09 - poprawki w komentarzach libgadu, by w przyszłości móc w łatwy sposób przerobić je skryptem na zgrabne ,,api reference'' (w) - przygotowanie gg_gethostbyname() pod wielobieżność (w) - poprawka płci w /list (neeo/w) - --without-debug naprawdę pozbywa się debugów z binarek (w) - poprawki dokumentacji (fig/w) - dodanie \$\I\d\$ w docach (fig/w) // 2002-06-08 - drobne poprawki w docach (w) // 2002-06-06 - nowy contrib Auto_Make_EKG (ciacho/w) - poprawka config.h.in (murphy,klith/w) // 2002-06-05 - poprawka gg_saprintf (krzak/s) - angielska wersja ekl2.man (w) // 2002-06-04 - poprawka libgadu.h (adaml/w) // 2002-06-03 - odśmiecanie libgadu.h (adaml/w) - poprawka libgadu.h, brak include'a config.h (murphy/w) // 2002-06-02 - poprawka ,,set dcc_ip'' (adwol/w) - poprawka emotikonów (fig/w) // 2002-05-29 - dodanie patcha na CONFIG_DIR (orzech/s) - arim.theme (arim/w) // 2002-05-28 - contrib/getekg.sh (arim/w) - zabijanie ioctld przy SEGV (perry/d) // 2002-05-27 - update ekl2.sh (tri10o/w) - zmiana ,,--ioctl-daemon-path'' na ,,--ioctld-path'' (w) - poprawka emotikonów. znowu (w) - poprawka potencjalnego format-vulnerability (w) // 2002-05-26 - uaktualnienie i poprawki opisu protokołu (adaml/w) - wywalenie protocol.txt (w) // 2002-05-25 - literówki w dokumentacji (fig/w) - poprawki themeów (theKnight/w) - poprawki pagera (seba,adwol/w) // 2002-05-23 - usunięcie -o, dodanie komend, dodanie docs/emoticons.txt (adwol/w) - poprawka segfaulta w wyświetlaniu emotikonów (adwol/w) // 2002-05-22 - poprawka wysyłania do nieznajomych (kalkos/w) - dodanie ostrzeżeń do dokumentacji themów (theKnight/w) - potok sterujący za pomocą parametru -c (adwol/w) - wykonywanie komend w trybie wsadowym (adwol/w) - obsługa emotikonów (adwol/w) // 2002-05-19 - poprawka configure/zle includowanie (s) - poprawka examples/Makefile.in (jojo/w) - update arim.theme (arim/w) - poprawka rozpoznawania płci. bierze najpierw imię, potem ksywę. dlatego ,,kuba'' powinien mieć wpisane imię ,,jakub'', jeśli nie chcemy z niego robić dziewczynki (arim/w) // 2002-05-18 - poprawka reakcji na zmiany stanu (scooty/w) // 2002-05-17 - dodany arim.theme (arim/w) - poprawka themeów rozłączania (arim/w) - DUŻE zmiany w autoconfie i Makefileach (w) - poprawione wykrywanie płci w list (gawrysz/w) - s/ioctl_daemon/ioctld/ (w) - poprawka rizonów przy reconnecie (gawrysz/w) - poprawka pagera i autosave'a (wielu/w) - mały rewrite obsługi gg_notify (w) // 2002-05-16 - poprawka endianów w kolorkowych pakietach (murphy/w) - dodane zdarzenia ,,sigusr1'' i ,,sigusr2'' odpowiadające sygnałom (joshua/w) - dodana akcja ,,command'', która wywołuje podaną komendę (w) - wysyłanie wiadomości do wielu odbiorców (wojboj/w) - poprawka rejestracji (scooty/w) // 2002-05-15 - poprawka listowania (joshua/w) - usunięcie wykrywania niewidocznych (w) - błędy w F1 (w) - można tylko raz zarejestrować numerek w ciągu sesji, by dzieciom trochę utrudnić zabawę w polowanie na numerki (w) - rozpoznawanie płci. szczegóły w docs/themes.txt (w) - ukryta zmienna ,,protocol'' w ekg pozwala szybko zmienić wersję protokołu, żeby sprawdzić jakiś egzotyczny ficzer (w) - zmienne liczbowe można wpisywać jako heksadecymalne, poprzedzające je tekstem ,,0x'' (w) // 2002-05-14 - małe poprawki w dokumentacji (w) // 2002-05-09 - dodanie debian/ (phantomik/w) - Ctrl-C zachowuje się jak w bashu -- czyści linię, nie wychodzi (adwol/w) - ujednolicone zachowanie Ctrl-D i ,,quit'' (adwol/w) - usunięcie użytkownika zaznacza zmianę konfiguracji (adwol/w) - poprawka array_make() (adwol/w) - poprawka stanów po reconnekcie (gawrysz/w) // 2002-05-07 - poprawka autosave (baseciq/w) - find w query szuka rozmówcy (dawszy/w) - update docs/on.txt (w) - uaktualnienie ,,docs/vars.txt'' (d) // 2002-05-06 - poprawka autosave (baseciq/w) - dodana komenda ,,version'' (d) - ekg --version (d) - drobna poprawka w ,,docs/on.txt'' (d) // 2002-04-30 - poprawki docs/devel-hints.txt, dodanie docs/ULOTKA, na czerwono każe na początku czytać pomoc itd. (w) - skrypt themes/extract.pl (w) - jeśli w themie będzie ,,no_prompt_cache 1'', prompty nie będą keszowane (a to dopiero nowina!) i można przez to w nich dawać timestampy (w) - niedorobiony theme 2k2 (w) - zmiana licencji libgadu na LGPL (w) - dorzucenie plików COPYING (w) - poprawienie README (w) // 2002-04-28 - dokładniejsze ifdefowanie kodu dla ioctldaemona (w) - s/bzero/memset/ (w) // 2002-04-27 - obsługa F-ów pod konsolą FreeBSD (maciekk/w) - poprawka reasonów przy autoawayu (gawrysz/w) - poprawka themeów (gawrysz/w) - poprawka synchronicznych połączeń (azzie/w) // 2002-04-25 - sekwencje F1 i F2 dla putty (jmk/w) - poprawka dla nie-gnu-kompilatorów (speedy/w) // 2002-04-24 - poprawka autoawaya (gawrysz/w) // 2002-04-23 - libgadu: s/gg_alloc_sprintf/gg_saprintf/ (w) - ekg: s/gg_alloc_sprintf/saprintf/ (w) - sensowny pager reagujący na zmiany rozmiaru terminala (w) - podbindowanie prostego helpa pod F1 (w) - krótka i zwięzła lista aktywnych i zajętych użytkowników pod F2 (w) // 2002-04-22 - poprawka ,,dostępny z opisem'' (gawrysz/w) - uzupełnienie themeów (gawrysz/w) - poprawka ,,set proxy'' (seba/w) - poprawki promptów, dodanie readline_prompt_invisible (gawrysz/w) - dostępny z opisem w /list (gawrysz/w) - back i invisible dobrze pokazują opisy (gallanonim/w) // 2002-04-19 - obsługa dostępnego i niewidocznego z opisem (w) - literówki w dokumentacji (FIG/w) // 2002-04-18 - rewrite kodu łączenia się z serwerem, nie działa jeszcze z proxy (w) - usunięcie zmiennych ,,proxy_*'' na rzecz jednej ,,proxy'' (w) - dodanie zmiennej ,,server'', opis w ,,docs/vars.txt'' (w) - porządki w cvsie. usunięcie starych i niepotrzebnych plików (w) - poprawka błędnych statusów (wielu/w) - porządki w Makefile'ach i configure.in (w) - update faq (w) - zmiana w api, parametry gg_login() (w) - poprawka _msg (seba/w) - poprawka kodu proxy, już działa jak trzeba (w) - poprawka statusów (w) // 2002-04-16 - zmienna ,,query_commands'' (robson/w) - usunięcie ,,ordering cd'' -- błędy na starszych solarisach (M.Przadlo/w) - update readme w zakresie wysyłania bugreportów (w) - poprawka segfaultu przy błędach w pubdir (robson/w) - prawidłowy host w gg_change_info() (robson/w) - możliwy błąd w completion (seba/w) // 2002-04-12 - poprawki kodu formatów, nie wywala klienta (w) - poprawki kodu dcc. odbieranie nie-za-maskaradą działa (w) // 2002-04-11 - uaktualnienie docs/on.txt (jmk/w) - poprawka tab completion (gawrysz/w) - dodanie opisu protokołu dcc w pliku docs/dcc-protocol.txt (ws/w) - poprawka segfaulta przy userliscie na serwerze (dyziu/w) // 2002-04-09 - formatowanie akcji zdarzeń. od teraz %1 w akcji oznacza uin nadawcy, %2 nazwę, jeśli jest w userliście albo numerek (w) - poprawka \n na \r\n przy awaryjnym zapisie userlisty (nie-pamiętam-kto/w) - config_read() poprawnie obsługuje komentarz typu ,,//'' (D.Jarosz/w) - posortowanie poleceń w tablicy commands (D.Jarosz/w) - poprawka w docs/api.txt zmiana libgg -> libgadu (D.Jarosz/w) - przymiarka do akcji ,,exec'' (w) - ogłaszanie userlisty po ,,list --get'' (cooler/w) - poprawka helpa ,,disconnect'', dopisanie rizonu (cooler/w) // 2002-04-04 - drobna poprawka w funkcji correct_event() (D.Jarosz@elka.pw.edu.pl/d) - dodana obsługa sygnału zmiany rozmiaru okna (d) // 2002-03-31 - poprawka ,,reconnect'' (d) // 2002-03-30 - poprawka helpa ,,list'', bo zaczynają mnie denerować listy o -g (w) - uaktualnienie ekgnv.sh (jojo/w) - losowany opis przy ,,auto_away'' w razie potrzeby (d) // 2002-03-29 - wyrzucenie ekl.pl z Makefile.in (d) - dorzucenie ekl2.pl autorstwa smarkacza (smarkacz/w) - poprawka wczytywania sekwencji z themów przy ,,on'' (d) - poprawka pagera przy ,,list'' i ,,help'' (eileen/d) - losowanie opisu przy ,,disconnect'' w razie potrzeby (d) // 2002-03-28 - dodana zmienna ,,log_status'' (d) - uaktualnienie docs/vars.txt (d) - przeniesienie contribów z docs/ do contrib/ (w) - dodanie contrib/ekgnv.sh ściągającego i budującego nową wersję (jojo/w) - dodane zmienne ,,away_reason'' oraz ,,random_reason'' (d) - poprawka przy ,,display_notify'' (eileen/d) // 2002-03-27 - akcja ,,beep'' przy ,,on'' (smarkacz/d) // 2002-03-26 - numerek i stan w ,,list user'' (klith/w) - uaktualnienie klith.theme (klith/w) - poprawki niewidzialnych (klith/w) - pokazywane opisy przy ,,away'' i ,,quit'' (klith/w) - pager przy ,,help'' (wojboj/w) - zdarzenie ,,invisible'' dla komendy ,,on'' (d) - uaktualnienie docs/on.txt (d) // 2002-03-25 - format_string() przy wyświetlaniu krótkich helpów (d) - poprawka cp->iso w opisie własnej zajętości (wasyl/w) - poprawka segfaulta przy /reconnect (anonimowy darczyńca/w) // 2002-03-24 - domyślny powód nieobecności w zmiennej ,,quit_reason'' (matias/w) - poprawka inkludów readline (seiko/w) - obsługa niewidocznych użytkowników (klith/w) - poprawka poprawki mkdir (wasyl/w) - kolejna poprawka wykrywania readline (wojboj/w) // 2002-03-23 - porządki w kodzie i Makefile (wojboj/w) - dodany ekl2.sh (tri10o/w) - ,,find'' bez parametrów mówi o sobie (w) - poprawka obsługi parametrów komend (wasyl/w) - konwersja iso->cp przy szukaniu (wasyl/w) // 2002-03-20 - wyłączenie tab completion w wielolinijkowych mesgach (gawrysz/w) - literówki w README (celtique/w) // 2002-03-18 - poprawka błędu w obsługi statusu (kuki/w) - konwersja cp-iso w opisach stanów (noname/w) - powód nieaktywności w ,,quit'' (klith/w) // 2002-03-17 - bzdurka w helpie (cry/w) // 2002-03-14 - poprawka s/ /\t/ w Makefile.in (booyas/w) // 2002-03-13 - fix Makefile.in, install -d $(prefiX)/bin (gawrysz/w) - poprawka dopełniania w query (gawrysz/w) // 2002-03-12 - ,,list --wait'' czeka na wciśnięcie klawisza po zapełnieniu ekranu. nie do końca dopracowane, ale działa. (jojo/w) // 2002-03-11 - mam drania! nie powinno segfaulcić przy zmianie stanu z tekstem. (w) - poprawka kodu kolorków. teoretycznie nie powinno wywalać błędów, ale głowy nie dam, bo nie mam jak tego sprawdzić. (w) // 2002-03-10 - dodanie ładniej obsługi segfaultów - wyświetla komunikat i zrzuca konfigurację i userlistę do ~/.gg/{config,userlist}.$PID (w) - rewrite kodu obsługi argumentów. nie będzie już niescisłości typu ,,list --googoo''. // 2002-03-09 - tab completion przy query nie dopełnia do nicka rozmówcy, bo i po co, i zostawia w spokoju ,,/'' przy dopełnianiu komend (jojo/w) - wciśnięcie enter w pustej linii w query nie wysyła niczego (w) - literówka w helpie (jojo/w) - ,,const char'' w libgadu, gdzie trzeba (tomee/w) - poprawka komendy ,,status'' (w) // 2002-03-08 - próbna obsługa kolorków. (w) - obsługa opisów stanów -- wyświetla przy połączeniu, zmianie stanów. (w) - komenda ,,away'' ma parametr, który określa powód. (w) - podbicie wersji do 0x15. raz kozie śmierć. (w) - poprawka nowości (kfazi/w) - obsługa EINTR w select() (eileen/w) // 2002-03-07 - poprawka desciptor-leaka. nie powinno wywalać już ,,too many open files'' gdy serwer leży i libgadu stara się łączyć w kółko. (w) // 2002-03-06 - nowości w docs/protocol.*, powody nieobecności (adaml/w) - dodanie do gg_search_request pola ,,start'' mówiącego, od którego wyniku ma być pokazywane. dodanie parametru ,,start'' do funkcji gg_search_request_mode_*() (meecash/w) - dodanie parametru ,,--start'' do komendy ,,find'' (w) - poprawka głupiego błędu z watches (kfazi/w) // 2002-03-04 - poprawka prepare_path(), bo na NetBSD nie można tworzyć ,,x//'' (dawszy/w) - dodatkowe sprawdzanie NULLi (kfazi/w) - poprawka list (kfazi,jmk/w) // 2002-02-26 - poprawka segfaulta, gdy dane watcha == NULL (kfazi/w) - theme (jojo/w) // 2002-02-21 - poprawka tab completion zmiennych (jojo@slackware.pl/w) // 2002-02-20 - poprawka w kodzie eventów ,,on'' (d) - poprawka poprawki ;/ (w) // 2002-02-19 - poprawka lib/dcc.c, brakujące GG_EVENT_DCC_CLIENT_ACCEPT (tomee/w) - poprawka dcc.txt, brakujące gg_dcc_port... (tomee/w) // 2002-02-17 - poprawka segfaulta w variable_add() (smiechu@rtr.fsi.pl/w) - wywalenie komendy ,,info'' (w) - poprawka command_set() i variable_find() (eileen/w) - poprawka zachowania ,,find'' (dawid@jarosz.one.pl/w) - poprawki dokumentacji, w miarę kompletny opis api dcc (w) // 2002-02-16 - rewrite kodu parsującego odebrane wiadomości (w) // 2002-02-15 - quickfix zapisywania theme'ów (jsm/w) - sensowne themey. zniknęło polecenie ,,theme''. zmienia się zmienną ,,theme'' (w) - duuużo poprawek w kodzie eventów ,,on'' (macpias@poczta.fm/w) // 2002-02-14 - s/libgg/libgadu/ w Makefile.in (tomee/w) // 2002-02-13 - poprawka algorytmu liczenia hashy (poprzedni też by dobry, ale ten ładniej implementuje ROR). autor kodu: bart/xtreeme, cryogen@host.sk (w) - podbicie GG_CLIENT_VERSION do 0x14 (w) // 2002-02-12 - można zmieniać swoje informacje w katalogu publicznym poleceniem ,,change'', ale niestety póki co, trzeba za każdym razem podawać wszystko (w) - poprawka gg_change_info(), żeby poprawnie urlencodowała pola (w) // 2002-02-11 - poprawka segfaultu w funkcjach poprawiających wynik array_make() (w) - poprawka ,,list'', zmiana informacji działa jak trzeba (dawid@pj190/w) // 2002-02-10 - przerzucenie wszystkich funkcji userlisty (w tym modify) do jednego polecenia ,,list''. userlista z serwera to ,,list --get'', na serwer ,,list --put'' (w) - drobne poprawki w docach (w) - drobne poprawki w dcc i http (w) // 2002-02-09 - nowe funkcje array_make() i array_free() służą do ładnego dzielenia tekstów na pola. obsługuje eskejpowanie, cudzysłowie itp. dzięki czemu działają konstrukcje typu ,,msg "miś yogi" cześć'' (w) - nowe logowanie wiadomości, tak jak wspomniałem na ekg-devel (w) - obsługa listy kontaktów na serwerze (w) - komendy ,,_ul_get'' i ,,_ul_put'', bo póki co, nie mam pomysłu, jak to rozwiązać (w) - poprawki w dokumentacji. początek htmlizacji protokol.txt (w) // 2002-02-08 - dopisane externy do zmiennych w libgadu.h (tomee/w) - dopisana nowa funkcja hashowania hasła. nie działa. później sprawdzę (ajron/w) // 2002-02-07 - już nie dodaje ,,obcych zmiennych'' przy /set (w) - auto_save, domyślnie wyłączona (cry/w) - poprawki MacOSX'owe - teraz powinno sie komplikowac [z fink'iem] (s) - biblioteka dzielona bedzie komplikowana dopiero po wybraniu opcji --with-shared przy configure (s) // 2002-02-06 - kosmetyka, dodanie obslugi akcji "play" (s) - poprawka --ioctl-... w helpie, bo się nie kompilowało na gcc 3.0 (w) - dodane exit(0) za execl() ioctl-daemona, bo przy jego braku program szedł dalej i działały dwie sesje ekg (w) - wydzielenie kodu userlist i ignorowanych do userlist.c, dodanie kodu obsługi grup użytkowników (w) - czyszczenie stanu userów po rozłączeniu (w) - komenda ,,list '' wyswietla informacje o danej osobie z listy kontaktów (w) - komenda ,,modify --group ...'' może dodawać lub usuwać użytkownika z danej grupy (w) - parę fixów, żeby funkcje systemowe na pewno nie dostały NULL jako argumentu (w) - kopirajty od 2001-2002 i dopisanie vinila gdzieniegdzie (w) - s/libgg/libgadu/ w examples/ (w) - wywalenie ekg.c do ekg.o, niech się na końcu linkuje wszystko i niech rekompilacja pakietu będzie szybsza (w) - przeniesienie zmiennych do listy. dzięki temu będzie zachowywał grzecznie wszystkie ustawienia innyc klientów, głównie GNU Gadu (w) - porzadki w zmiennych -- wszystkie funkcje variable_* (w) - porzadki w konfiguracji -- wszystkie zmienne config_* (w) - zabija dzieciaki przy wyjściu, typu wavplay/mpg123/resolver (w) - poprawki w dokumentacji (w) // 2002-02-03 - kosmetyka "ioctl" (s) - --with-ioctl komplikuje tez ioctl_daemon (na razie wspierane tylko na linuksie) (s) // 2002-02-02 - dodana komenda ,,on'' (d) - dodany docs/on.txt (d) - dodany ioctl_daemon (d) - poprawka docs/ekl.pl (d) // 2002-01-29 - zmiana libgg na libgadu. WSZĘDZIE. żeby nie koligowało z libgii, libggi i kilkoma innymi. przykro mi. (w) // 2002-01-28 - poprawka liczenia hasha z hasła, s/char/uchar/ (adaml/w) - dodana komenda ,,reconnect'' (matias@dexter.zst.bytom.pl/w) - poprawka docs/api.txt (jajcus@bnet.pl/w) // 2002-01-22 - dodane ,,--group'' w helpie do ,,modify'' (adaml/w) - poprawka obsługa wielolinijkowych sysmsg (jajcus@bnet.pl/w) - zamykanie połączenia jeszcze raz dla pewności po nieudanym połączeniu (jam/w) - wywala błąd w przypadku braku readline{,-devel} (leszek@php.net/w) // 2002-01-17 - poprawka base64 na !linux'owych systemach ;>>> (p/kfazi) // 2002-01-12 - coś mi się dziwnie zapętliło i rzucało ,,header recv() = -1'' cały czas, co nie powinno się zdarzyć, ale na wszelki wypadek dorzuciłem ograniczenie do 10 prób recv()owania. (w) - dorzucony plik docs/devel-hints.txt będący moim pierwszym postem na listę ekg-devel ze wskazówkami dla developerów. (w) // 2002-01-05 - tak siedziałem i w pld stwierdziłem angielski manual. dodałem go i zarazem poprawiłem polski [p/gotar@pld/s] // 2001-12-26 - tak sobie podczas świątecznego obiadu wymyśliłem, że napiszę funkcję itoa(), która zastąpi śmieszne konstrukcje typu { char buf[16]; snprintf(buf, 16, "%d", x); return x; }. i napisałem. (w) // 2001-12-18 - encode_base64() i decode_base64() już działają (w) - hasła są zapisywane w base64. są poprzedzane znakiem '\001', by odróżnić je od haseł zapisanych plaintextem. to nie jest żadne zabezpieczenie, więc można sobie darować posty na bugtraq, że złamano szyfrowanie haseł w konfigach ekg. to ma chronić przed osobami postronnymi, zapamiętaniem hasła po zerknięciu do pliku itd. od razu mówię, że można je odkodować przez ,,echo haslo | mimencode -u'' (w) // 2001-12-17 - gg_send_packet() o zmiennej ilości parametrów (a) - informowanie o wiadomościach konferencyjnych przez API libgg (a) - poprawki w gg_watch_fd_connected() (w) - dodanie gg_session->last_event (a/w) - dodana komenda ,,_ping'' (w) - uaktualnienie docs/protocol.txt, GG_DISCONNECTING (w) // 2001-12-16 - zmiana hasła komendą ,,passwd'' (w) - fix gg_change_passwd(), żeby działało (w) - ,,dcc get'' działa (w) - poprawka README i ChangeLoga, żeby dały się łatwo zHTMLizować (w) - nowa strona http://dev.null.pl/ekg/ (w) - poprawki wysyłania plików. niestety nie było okazji sprawdzić (w). // 2001-12-14 - szkielet zmian w katalogu publicznym / biblioteka (s) - dodany event GG_EVENT_PONG (w) - ekg ignoruje SIGPIPE (arekm/w) - dodana komenda ,,query'' (d) // 2001-12-12 - poprawka segfaultu przy timeoutach (w) - poprawka błędu searcha na systemach innych niż mój (charvel/w) // 2001-12-09 - poprawka configure gdzie make nie jest make (s) // 2001-12-08 - obsługa wiadomości systemowych (s) // 2001-12-07 - poprawka pytania o zapis konfiguracji przy wychodzeniu. bez theme'ów nie trzeba się martwić o złe prompty (w) - dodanie timeoutów do libgg i korzystanie z nich w kliencie. każda sesja ma pole ,,timeout'', które biblioteka ustawia na GG_DEFAULT_TIMEOUT (w tej chwili 30 sekund) przy każdej operacji, lub -1 jeśli nie ma być timeout (GG_STATE_CONNECTED). klient sam musi zadbać o to, żeby zmniejszać wartość tego pola co sekundę i zatroszczyć się o reakcję w przypadku zejścia do zera (w) // 2001-12-06 - dodana funkcja wysyłania hasła juzerom do libgg (thrull/w) - dodana lista ,,watches'' w kliencie. dzięki niej sobie grzeczie przemiata ważne deskyptory. dzięki niej może chodzić równocześnie kilka searczy. i łatwiej się połapać. (w) - dodana komenda ,,remind'', która powoduje wysłanie hasła na skrzynkę (w) - dodanie funkcji zmiany hasła (w) // 2001-12-04 - kolejny rewrite http. jeszcze czeka sporo poprawek, ale kształt jest już nadany. drobne poprawki w libgg (w) // 2001-12-03 - przygotowanie do obsługi http proxy (s) - obsługa http proxy (w) - poprawki http proxy (s) - wcześniej dodane ,,find --stop'' (fahren/w) // 2001-12-02 - algorytm obliczania hasha http (coxoc/a) - przymiarka do komendy register (s) - zmiana znaczenia komendy info (s) // 2001-11-26 - przygotowanie do obsługi rejestracji (w) - wordwrapping, haha! nowe formaty {message,chat}_line{,_width} do ładnych mesgów z rameczkami i takimi tam (w) // 2001-11-25 - GG_CLASS_OFFLINE = GG_CLASS_QUEUED (arekm/s) - totalna reorganizacja zrodel... mam nadzieje ze sie komplikuja (s) - more TODO (s) - reorganizacja libgg. podział na mniejsze pliki. wydzielenie obsługi http z sercza. i takie tam bzdurki (w) - popsucie paru dumpów (w) // 2001-11-22 - GG_CLASS_OFFLINE w libgg.h i docs/protocol.txt (THRull/w) - sic.theme - update TODO/FAQ (w) // 2001-11-21 - poprawka configure.in, wykrywanie rl_set_prompt() (w) // 2001-11-20 - mocno poprawiona obsługa ustawień początkowych (w) - żegnamy się z ~/.gg/autoexec, skoro mamy zmienną ,,theme'' (w) - przy readline 4.x będzie ładnie zmieniać prompta przy awayu (w) - ,,ekg --help'' i okolice (w) - dodany include do libgg.h, poprawka INADDR_NONE (w) - stan o kliencie jest przechowywany w zmiennej ,,default_status'', a nie jak dotychczas, w ,,away'' i ,,private''. stan można też podać przy uruchamianiu. - możliwość zmiany gg_session->initial_status w libgg zaraz po wywołaniu gg_login(). trochę nieładne, ale ciężko to zrobić inaczej ;/ - posortowanie listy zmiennych (w) - bugfixy ,,find'', poprawnie akceptuje --male, --female, --active, dodana płeć do helpa (w) - jest zmienna ,,display_notify'' (w) - uaktualnione docs/protocol.txt, konferencje (w) - popsucie 10 innych rzeczy (w) - było sobie FAQ (s/w) // 2001-11-19 - wiecej instalowania... (i/drake) - przygotowania do base64, theme'y będą szukane w $(datadir)/ekg/themes, ~/.gg i ~/.gg/themes (w). - nowa zmienna "theme" ... - ustala "defaultowy" theme po odpaleniu ekg (s) // 2001-11-18 - można usunąć wartość zmiennej tekstowej przez ,,set -nazwa'' (w). - porządkowanie errno (w). - feeg.theme. // 2001-11-15 - poprawki dokumentacji (shasta/w). - dodane dzwięki przy wiadomościach -- zmienne ,,sound_...'' (feeg/w). - ,,display_ack'': 0 - nie pokazuje nic, 1 - pokazuje wszystkie, 2 - tylko dostarczone, 3 - tylko zakolejkowane. (i/klith). - klith.theme. // 2001-11-11 - make shared/static + jakis tam spec dla rpm'a... (speedy) - poprawiona dokumentacja [ja chce wpisywac polskie krzaki i nie wiem jak] (wojtekka) - logowanie wielolinijkowych wiadomosci (wojtekka) - poprawiony segfault na bsd w pewnych warunkach (smarkacz/w) // 2001-11-04 - dalsze psucie https... teraz jest zawsze i wszedzie (speedy) // 2001-11-03 - popsuta kompilacja na broken solaris ;> [sprawdzone na solarisie 2.7/gcc] (speedy) - tryb https - juz dostepny ;> ogolnie to milo mnie autor gg zaskoczyl praktycznie jest juz jeden format. errr w razie błędu połączenia appmsg:8074 próbuje się łączyć z portem :443 tego samego hosta (speedy) - mamo, mamo, a vinil popsuł czejdżloga ;) ja chciałem przypomnieć, że naprawiłem parę memory leaków i leakdet.pl (w) // 2001-11-02 - w razie błędu połączenia z appmsg:80, próbuje się łączyć po :8074 z tym samym hostem (w). - dopisałem urla do README, bo mam już dość pytań, skąd to ściągnąć (w). - wywalone z IDEAS to, co już zrobione (w). - po ,,disconnect'' nie powinien próbować się łączyć (w). - poprawka segfaultu na nie-x86 (w). // 2001-11-01 - plumk, dodatkowe parametry ,,list'' (wojtekka). - sortowana userlista, dodana list_add_sorted() w dynstuff.c (wojtekka). - ,,modify'' już ma przypadkiem zostawionego printf()a (wojtekka). - ,,add'' może przyjmować takie same parametry jak ,,modify'' (wojtekka). - dodany prompt do rozszerzonych helpów (wojtekka). - poprawka README (wojtekka). // 2001-10-31 - popsuty manual... docs/ekg.man... (?/speedy) - poprawka manuala, configure.in i aclocal.m4 do autoconfa 2.5x (wojtekka). // 2001-10-27 - popsulem configure [kompatybilnosc z termcapem + wymuszenie curses --without-termcap + mozliwosc wylaczenia -Wall -ggdb --without-debug] pierwsze (i/wojtekka), drugie (i/undefined) - poprawione gg_alloc_sprintf() na maszynach pre-C99 (p/wojtekka). // 2001-10-26 - lekko poprawiłem obsługę dzieciaków. nie wait()uje na każdy z listy po kolei, tylko na _wszystkie_ i potem po kolei sprawdza, czy przypadkiem nie jest na liście. powinno zlikwidować dziwne przypadki tworzenia zombie i zajmowania całych dostępnych zasobów (p/wojtekka) - fix commands.c dla BSD (p/wojtekka) // 2001-10-24 - nudny dzien w pracy... hmm.. popsulem configure... (?/speedy) // 2001-10-21 - nudne niedzielne popołunie... hmm, popsuję może cvsa vinilowi, hehe ;) (?/wojtekka) - dodane wszystko, co leżało u mnie w ~/src/gg, a nie było dołączane do snapshotów (p/wojtekka) // 2001-10-17 - czyszczenie userlist [statusow] (i/agaran) - mozliwosc wyboru usera ekg -u - konfig pobiera z ~/.gg//config - cvs ;> // 2001-10-14 - dodana komenda ,,alias'' (p/drg). - dodany docs/ekl.pl (p/drg). - można zmieniać prompta w themes ustawieniami ,,readline_prompt'' i ,,readline_prompt_away'' (i/drg). - fix command_alias (p/drg). - time.h w libgg.c (p/drg). // 2001-10-09 - dodane pole ,,last_pong'' w strukturze ,,gg_session'' zwierające czas otrzymania ostatniego pakietu GG_PONG (i/tomee). - dodana komenda ,,private'' włączająca lub wyłączająca tryb tylko dla znajomych z GG 4.6 (p/pkot,vinil). - dodana komenda ,,status'' wyświetlająca aktualny stan (i/Sydney Green). - stan klienta jest zapisywany komendą ,,save'', więc może wejść na sieć w trybie tylko dla przyjaciół lub zajęty itd, itd. - więcej debugów w libgg_search.c (i/tomee). - poprawki w docs/protocol.txt (i/wzik). // 2001-10-08 - dopisana zmienna ,,bold_font'' żeby nie psuło konfigów GNU Gadu (p/thrull). // 2001-10-05 - zmienna display_ack (i/outsider). - informacje o nickach w changelogu będą poprzedzane literką 'i' w przypadku propozycji lub pomysłu, 'b' w przypadku bugreportu lub 'p' w przypadku gotowego patcha lub źródełek. - zmienna completion_notify (i/rekin). - dorzucony jamzed.theme (p/jamzed). - automatyczne dopisywanie rozszerzenia przy ładowaniu theme'ów (i/nie pamiętam, kto to proponował -- niech się zgłosi ;)) // 2001-10-02 - chmody zapisywanych plików (p/ascent). - poprawka komunikatu przy EINPROGRESS w gg_connect(). - fixy dla AIXa (p/arturp). // 2001-10-01 - poprawki na alphę. - /cleartab (i/szok). - poprawki debugowania dla MacOS X (p/vinil). - fix segfaultu przy otrzymaniu notify usera spoza listy (b/ascent). - wykrywanie czy $cc obsługuje -pipe (p/ascent). - pyta o zapisanie konfiguracji przy wychodzeniu (p/pkot). - wywalenie #ifdefów GG_DEBUG, niech sobie będzie na stałe. w końcu to wersja rozwojowa. i się powinno kompilować na MacOS X (p/vinil,wojtekka). - wywalenie z testowania termcapa. dzięki temu od ręki kompiluje się na IRIXie (vinil wiedział, nie powiedział, a to było tak...) - cleanup w list_remove() (p/pkot). - poprawka wykrywania -pipe (p/vinil). - info o kompilacji na MacOS-ie w README (i/vinil). // 2001-09-30 - numerek snapshotu w themes.c (b/jack). - update docs/protocol.txt (p/wzik). - configure wykrywa readline z pakietów netbsd (b/socrtp). - poprawka bigendianów (p/vinil,wojtekka). // 2001-09-29 - case insensitive tab completion (i/pkot). - poprawka gg_urlencode(), bo segfaultowało z polskimi localami. - ,,make shared'' dołącza libgg_search.o (p/tomee). // 2001-09-28 - poprawka command_del() -- sensowniejsze komunikaty (b/ascent). - poprawka command_add() -- nie można dodać dwóch userów o tych samych ksywach (b/ascent). - poprawka zapisu ustawień. tworzy ~/.gg (b/madmax). - ,,configure --help'' nie idzie dalej (b/madmax). // 2001-09-27 - poprawka s/ENOTSUP/EINVAL/ bo OpenBSD nie ma tego (b/phantom). - poprawka add_user() (pkot). - dodana komenda ,,modify''. - zmiana licencji na GPLv2, przygotowania do pierwszego publicznego snapshotu. // 2001-09-26 - poprawka płci przy formularzu szukania ludków (b/arekm). // 2001-09-25 - rewrite obsługi listy kontaktów, ignorowanych i theme'ów. nie mają już sztywno ustalonych limitów. doszła lista dzieciaków. - obsługa dzieciaków na waitpid(), dzięki czemu wiadomo który i jak się zakończył. - przy wysyłaniu smsów, zamykane są wszystkie deskryptory, przez co nie będzie śmiecić na ekranie. // 2001-09-24 - poprawka wait(). na wolniejszym sprzęcie select() potrafił się wieszać, jeśli przyszedł SIGCHLD. - nie robi autoawaya, gdy user jest niewidoczny (miskoala). - nie loguje jeśli nie ma logować (zdzichu). // 2001-09-23 - poprawki parsera komend. - klient potrafi szukać userów. szczegóły w ,,help find''. jako parametr można podać nicka z książki lub sam numerek, pomijając fikuśne opcje tej komendy. i tak, wiem, czasami nie wiadomo dlaczego wywala błędy. - ekg odpalone z parametrem '-n' albo '--no-auto' nie łączy się od razu z serwerem. do tego '-d' dorobiło się długiej nazwy '--debug'. - poprawka gg_urlencode() żeby nie korzystało isalnum(), bo locale mogłyby popsuć (arekm). - configure wykrywa endiany i nie bawi się w setki #ifdef'ów (kod vinila) - wywalona obsługa wyjątków przy select(), bo powodowała tylko dziwne problemy z nieistniejącymi błędami. - dodane i poprawione mnóstwo wpisów gg_debug(). - dodane opisy funkcji w stuff.c, themes.c i vars.c. - poprawione cp_to_iso(). - poprawki poprawek parsera komend (bugreport jack'a). - poprawki Makefile.in. - poprawka loga poprawki poprawek -- dopisanie apostrofa (jack zgłosił). - zmienne ,,beep_msg'', ,,beep_chat'', ,,beep_notify'' (jack). - wielolinijkowe mesgi. wystarczy zamiast treści wiadomości wpisać ,,\'', wklepać wiadomość i zakończyć linią zawierającą samą kropkę. żeby anulować wystarczy ^D. i tak, niestety jak w trakcie pisania coś przyjdzie, to potnie wiadomość. póki co. - fix polskich znaczków. - poprawne dopełnianie parametrów przy skróconych komendach (wysek). // 2001-09-22 - poprawiony błąd w configure po checkinie. - interfejs szukania luserów. póki co, klient jeszcze z niego nie korzysta ale jest dołączony prosty programik w `docs/search.c'. niestety może się wywalać na egzotycznych systemach z popsutym vsnprintf()... :/ - niewielkie zmiany w api. gg_login() zwraca zaalokowaną strukturę `gg_session' albo NULL, którą zwalnia się przez gg_free_session(). zmieniona nazwa funkcji gg_watch_event() na gg_watch_fd(). - za to w libgg_search.c duuuże zmiany w api. dołączony plik examples/search.c powinien rozjaśnić nieco. poza tym, dopisałem jakieśtam komentarze przy funkcjach. haha. - read_file() czyta z pliku linię i dynamicznie alokuje. dzięki temu maksymalny rozmiar linii w konfiguracji, autoexecu i themes jest zależny wyłącznie od dostępnej pamięci. - dopełnianie do lewej, do prawej, spacjami, kropkami, podkreśleniami i takie tam inne bzdururki. szczegóły w docs/themes.txt // 2001-09-20 - nowy format `prompt2', żeby ładnie i kolorowo odróżniać wiadomości od innych tekstów wywalanych na ekran. - zmienił się format userlisty, żeby był zgodny z eksportem/importem windzianego klienta. i tak, linie kończą się `\r\n'. później dopiszę jakieś zarządzanie tym. // 2001-09-19 - wygląda na to, że mój magiczny configure się wywalał tam, gdzie shellem nie jest bash tylko na przykład tcsh. poprawiłem, działa niektórym ;) - poprawiona kolejność include'ów i mały fix w themes.c, dzięki czemu nie rzuca warningami na OpenBSD. - poprawione wykrywanie readline >= 4.x (dzięki wyskowi i zdzichowi). - sms_away, powiadamienie na komórkę o przychodzących wiadomościach, jakoś tak... podziękować wyskowi, bo podesłał patcha. // 2001-09-18 - configure, haha! - powinno pójść nawet na Irixie dzięki configure i patchom vinila. // 2001-09-17 - ładniejsze formatowanie w skrypcie ggsearch. - dane mogą przychodzić w kilku pakietach i nie będzie EAGAIN. jedynie nagłówek musi być w całości. w normalnych warunkach nie przyjdzie nigdy w kawałkach, więc jeśli klient się wywali, co coś bardzo dziwnego się dzieje z siecią ;) - poprawka /away (MisKoala). - wywalenie kolorków z prompta. przynajmniej dobrze zawija. // 2001-09-16 - poprawki w formatowaniu unignore. - dopełnianie nazw zmiennych i ignorowanych. - jakieśtam poprawki w README. // 2001-09-15 - czytanie listy ignorowanych z ~/.gg/config. - zapis konfiguracji (zmiennych i ignorowanych). - bugfix parsowania skróconych komend. // 2001-09-14 - poprawka segfaultu w przypadku rozłączenia przez serwer (zgłosił martii). // 2001-09-13 - Makefile vs. PLDowe ncurses (bugreport jacka), // 2001-09-12 - parę bugfixów z reconnectem, - dodane komendy 'connect' i 'disconnect', - uin i hasło przeniesione do zmiennych. // 2001-09-11 - dodane '-lcurses', żeby się kompilowało pod dziwnymi systemami ;) - dodany tryb niewidoczny (patch vinila). - poprawiona reakcja na zerwanie połączenia. - zmienna 'auto_reconnect' w sekundach. - resolver nie zostawia już zombie. - update w docs/protocol.txt z nowymi ficzerami GG 4.6 (info od vinila). // 2001-09-09 - zmienne, ale jeszcze nie zapisuje ustawień. - logowanie (patch phantoma), log=1 loguje do pliku $log_path, log=2 do $log_path/$uin - można wyłączyć kolorki (zmienna display_color) - można wyłączyć beepanie (zmienna beep) // 2001-09-08 - blokujące sockety. - uaktualnienie opisu protokołu. // 2001-09-07 - dodane extern "C" i s/class/msgclass/, żeby się tomeemu kompilowało w C++. - do nick completion dodawane są nicki osób, które właśnie się pojawiły. - theme'y obsługują kolorowe tła. szczegóły w themes.c // 2001-09-06 - poprawione braki w obsłudze błędów. - początek przywracania blokującej obsługi socketów. - początki dokumentacji dla programistów - uzupełnione braki w komentarzach libgg.c i osobny plik API. // 2001-09-05 - poprawione klasy mesgów. nie wiem dlaczgo, ale teraz dochodzą potwierdzenia. - zmiana nazwy binarki z gg na ekg. - usunięcie wszystkich tekstów ,,G*du-g*du'' z pakietu, ponieważ to znak towarowy zastrzeżony. whatever ;) // 2001-09-02 - biblioteka jest nieblokująca. no dobra, część rzeczy jak czytanie http może się wywalić, jeśli nie dostanie od razu wszystkich danych, ale teoretycznie nie powinno się to przytrafić. nawet na moim magicznym łączu 28800 nigdy nie było problemu. kiedyś poprawię. trzeba tylko jeszcze poprawić komendy, żeby reagowały odpowiednio, jeśli klient się nie połączył jeszcze. - reconnect na każdym etapie. nie ważne, czy to zaraz po uruchomieniu czy w trakcie działania. w tej chwili czas, po którym się łączy jeszcze raz jest ustawiony na 5 sekund. - poprawione endiany, żeby działały i na solku. - do Makefile'a dopisana opcja ,,shared'' budująca bibliotekę dzieloną (przepis od tomee'go). - komendy wymagające połączenia będą krzyczeć, jeśli go nie ma. - automatyczne stawianie awaya po ponownym połączeniu. - autoaway działa tylko podczas połączenia. // 2001-09-01 - usunięcie strsep (vinil cośtam mówił). // 2001-08-30 - powinno kompilować się na bsd bez poprawek (vinil podał ifdefy). // 2001-08-29 długo mnie w domu nie widzieli, więc nie było dziennych snapshotów. jakoś tak. whatever. i jeśli ktoś ma jakieś uwagi, niech najpierw zajrzy do TODO i BUGS. - niby obsługuje EINTR przy read(), ale czasami jeszcze mówi, że rozłączono z powodem ,,Interrupted System Call''. - podział ,,send'' na ,,msg'' i ,,chat'' (Wiadomość i Rozmowa odpowiednio). i nie, nie ma żadnych osobnych okienek. - poprawiony błąd przy kompilacji, konfikt z - beepa przy wiadomościach. póki co nie ma możliwości wyłączenia innej niż zmianę w theme'ach. // 2001-08-25 - themes. domyślnie szuka w '~/.gg/default.theme'. - '~/.gg/autoexec' zawiera listę komend do wykonania po starcie, na przykład załadowanie jakiegośtam theme'u. - dwa przykładowe głupie theme'y w docs/, które można wrzucić do ~/.gg - poprawiony warning z rl_extend_line_buffer (zgłosił wysek), // 2001-08-23 - ignorowanie '/' na początku komendy, - 'make checkin', - timestamp przy otrzymanym mesgu, - reconnect 5 razy, - pokazuje powód błędu (connection refused itd), - poprawione unknown_uin_completion, - testowe komendy _add i _send, - tło mesgów, - tab completion działa jak trzeba, - eleet niebieskie tło mesgów (wiem, dalekie od ideału). $Id$ ekg-1.9~pre+r2855/Makefile.in000066400000000000000000000044241174410337000156700ustar00rootroot00000000000000# $Id$ srcdir = @srcdir@ prefix = @prefix@ datarootdir = @datarootdir@ datadir = @datadir@ mandir = @mandir@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ libexecdir = @libexecdir@ includedir = @includedir@ MAKE = @MAKE@ INSTALL = @INSTALL@ # all: configure compat @ekg@ @make_ekgwap@ ekg: cd src && $(MAKE) all make-ekgwap: cd ekgwap && $(MAKE) all examples: cd examples && $(MAKE) all compat: mkdir -p $@ # dep: cd src && $(MAKE) dep # configure: configure.in m4/* ./autogen.sh # install: all @install_ekg@ @install_ekgwap@ install-ekg: install-ekg-data install-ekg-man cd src && $(MAKE) install install-ekg-data: $(INSTALL) -d $(DESTDIR)$(datadir)/ekg/themes $(INSTALL) -m 644 $(srcdir)/themes/*.theme $(DESTDIR)$(datadir)/ekg/themes $(INSTALL) -m 644 $(srcdir)/docs/vars.txt $(DESTDIR)$(datadir)/ekg install-ekg-man: $(INSTALL) -d $(DESTDIR)$(mandir)/man1 $(INSTALL) -m 644 $(srcdir)/docs/ekg.man.en $(DESTDIR)$(mandir)/man1/ekg.1 $(INSTALL) -d $(DESTDIR)$(mandir)/pl/man1 $(INSTALL) -m 644 $(srcdir)/docs/ekg.man.pl $(DESTDIR)$(mandir)/pl/man1/ekg.1 install-ekgwap: $(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) -m 755 ekgwap/ekgwapd $(DESTDIR)$(bindir) install-ekl2: $(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) -m 755 $(srcdir)/contrib/ekl2.pl $(DESTDIR)$(bindir) $(INSTALL) -m 755 $(srcdir)/contrib/ekl2.sh $(DESTDIR)$(bindir) $(INSTALL) -d $(DESTDIR)$(mandir)/man1 $(INSTALL) -m 644 $(srcdir)/docs/ekl2.man.en $(DESTDIR)$(mandir)/man1/ekl2.1 $(INSTALL) -d $(DESTDIR)$(mandir)/pl/man1 $(INSTALL) -m 644 $(srcdir)/docs/ekl2.man.pl $(DESTDIR)$(mandir)/pl/man1/ekl2.1 # uninstall-ekg: rm -f $(DESTDIR)$(bindir)/{ekg,ekgwapd,ekl2.{sh,pl}} rm -f $(DESTDIR)$(libexecdir)/ioctld rm -rf $(DESTDIR)$(datadir)/ekg rm -f $(DESTDIR)$(mandir){/pl,}/man1/{ekg,ekl2}.1 # clean: @clean_ekg@ clean-examples clean-compat clean-ekg: cd src && $(MAKE) clean clean-examples: cd examples && $(MAKE) clean clean-compat: cd compat && rm -f *.o *~ # distclean: @distclean_ekg@ distclean-examples distclean-compat rm -f *~ config.log config.cache config.status config.h Makefile rm -f config.h.in configure aclocal.m4 distclean-ekg: cd src && $(MAKE) distclean distclean-examples: cd examples && $(MAKE) distclean distclean-compat: cd compat && rm -f *.o *~ ekg-1.9~pre+r2855/autogen.sh000077500000000000000000000004631174410337000156230ustar00rootroot00000000000000#!/bin/sh if test "$*"; then ARGS="$*" else test -f config.log && ARGS=`grep '^ \$ \./configure ' config.log | sed 's/^ \$ \.\/configure //' 2> /dev/null` fi aclocal -I m4 || exit 1 autoheader || exit 1 autoconf || exit 1 test x$NOCONFIGURE = x && echo "Running ./configure $ARGS" && ./configure $ARGS ekg-1.9~pre+r2855/compat/000077500000000000000000000000001174410337000151025ustar00rootroot00000000000000ekg-1.9~pre+r2855/compat/dirname.c000066400000000000000000000026611174410337000166720ustar00rootroot00000000000000/* * Copyright (c) 2003 Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif char *dirname(const char *path) { static char buf[PATH_MAX]; register const char *ptr; if (!path || !*path || !strchr(path, '/')) { strncpy(buf, ".", sizeof(buf) - 1); return buf; } for (ptr = path + strlen(path) - 1; ptr > path; ptr--) if (*ptr != '/') break; for (; ptr > path; ptr--) if (*ptr == '/') break; if (ptr > path) { for (; ptr > path; ptr--) if (*ptr != '/') break; if (ptr - path + 2 > sizeof(buf)) { errno = ENAMETOOLONG; return NULL; } strncpy(buf, path, ptr - path + 1); } else strncpy(buf, "/", sizeof(buf) - 1); return buf; } ekg-1.9~pre+r2855/compat/dirname.h000066400000000000000000000000411174410337000166650ustar00rootroot00000000000000char *dirname(const char *path); ekg-1.9~pre+r2855/compat/getopt.c000066400000000000000000000370371174410337000165620ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* Excessive comments removed by Wojtek Kaniewski */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ # ifndef const # define const # endif #endif #include #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE #ifdef __GNU_LIBRARY__ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ # if defined HAVE_LIBINTL_H || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif #include "getopt.h" char *optarg; int optind = 1; int __getopt_initialized; static char *nextchar; int opterr = 1; int optopt = '?'; static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; static char *posixly_correct; #ifdef __GNU_LIBRARY__ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } #ifdef __GNUC__ # if (!defined __STDC__ || !__STDC__) && !defined strlen extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC extern int __libc_argc; extern char **__libc_argv; # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } if (optind == argc) { if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } { char c = *nextchar++; char *temp = my_index (optstring, c); if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; if (*nextchar != '\0') { optarg = nextchar; optind++; } else if (optind == argc) { if (print_errors) { fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else optarg = argv[optind++]; for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { if (*nextchar != '\0') { optarg = nextchar; optind++; } else if (optind == argc) { if (print_errors) { fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ ekg-1.9~pre+r2855/compat/getopt.h000066400000000000000000000050641174410337000165620ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* Excessive comments removed by Wojtek Kaniewski */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif extern char *optarg; extern int optind; extern int opterr; extern int optopt; #ifndef __need_getopt struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif int has_arg; int *flag; int val; }; # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif #undef __need_getopt #endif /* getopt.h */ ekg-1.9~pre+r2855/compat/getopt1.c000066400000000000000000000040541174410337000166340ustar00rootroot00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* Excessive comments removed by Wojtek Kaniewski */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined __STDC__ || !__STDC__ #ifndef const #define const #endif #endif #include #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ ekg-1.9~pre+r2855/compat/scandir.c000066400000000000000000000044571174410337000167030ustar00rootroot00000000000000/* * Copyright (c) 2002-2003 Wojtek Kaniewski * Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #define __DIRENT_SIZE(d) (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name) + strlen((d)->d_name) + 1) int alphasort(const void *__a, const void *__b) { struct dirent **a = (struct dirent**) __a, **b = (struct dirent**) __b; if (!a || !b || !*a || !*b || !(*a)->d_name || !(*b)->d_name) return 0; return strcmp((*a)->d_name, (*b)->d_name); } int scandir(const char *path, struct dirent ***namelist, int (*select)(const struct dirent *), int (*compar)(const void *a, const void *b)) { int i, count = 0, my_errno = 0; struct dirent **res, *tmp; DIR *dir; if (!(dir = opendir(path))) return -1; while ((tmp = readdir(dir))) if (!select || (*select)(tmp)) count++; rewinddir(dir); res = calloc(count, sizeof(struct dirent*)); if (!res) { my_errno = errno; goto cleanup; } memset(res, 0, count * sizeof(struct dirent*)); for (i = 0; i < count; ) { tmp = readdir(dir); if (!tmp) { my_errno = errno; goto cleanup; } if (select && !(*select)(tmp)) continue; res[i] = malloc(__DIRENT_SIZE(tmp)); if (!res[i]) { my_errno = ENOMEM; goto cleanup; } memcpy(res[i], tmp, __DIRENT_SIZE(tmp)); i++; } closedir(dir); if (compar) qsort(res, count, sizeof(struct dirent*), compar); *namelist = res; return count; cleanup: for (i = 0; res && res[i] && i < count; i++) free(res[i]); if (res) free(res); closedir(dir); errno = my_errno; return -1; } ekg-1.9~pre+r2855/compat/scandir.h000066400000000000000000000003171174410337000166770ustar00rootroot00000000000000#include #include int alphasort(const void*, const void*); int scandir(const char*, struct dirent***, int (*select)(const struct dirent*), int (*compar)(const void*, const void*)); ekg-1.9~pre+r2855/compat/strlcat.c000066400000000000000000000020711174410337000167220ustar00rootroot00000000000000/* * Copyright (c) 2003 Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include size_t strlcat(char *dst, const char *src, size_t size) { register size_t i, j; size_t left, dlen; for (i = 0; i < size && dst[i]; i++) continue; dlen = i; left = size - i; for (j = 0; left > j + 1 && src[j]; j++, i++) dst[i] = src[j]; if (left) dst[i] = 0; while (src[j]) j++; return dlen + j; } ekg-1.9~pre+r2855/compat/strlcat.h000066400000000000000000000001211174410337000167210ustar00rootroot00000000000000#include size_t strlcat(char *dst, const char *src, size_t size); ekg-1.9~pre+r2855/compat/strlcpy.c000066400000000000000000000017121174410337000167470ustar00rootroot00000000000000/* * Copyright (c) 2003 Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include size_t strlcpy(char *dst, const char *src, size_t size) { register size_t i, n = size; for (i = 0; n > 1 && src[i]; i++, n--) dst[i] = src[i]; if (n) dst[i] = 0; while (src[i]) i++; return i; } ekg-1.9~pre+r2855/compat/strlcpy.h000066400000000000000000000001211174410337000167450ustar00rootroot00000000000000#include size_t strlcpy(char *dst, const char *src, size_t size); ekg-1.9~pre+r2855/configure.in000066400000000000000000000260501174410337000161330ustar00rootroot00000000000000dnl $Id$ AC_INIT(src/ekg.c) AC_PREREQ(2.50) AC_CONFIG_HEADERS(config.h) AC_SUBST(OBJS) AC_SUBST(IOCTLD_OBJS) AC_SUBST(PC_REQUIRES) AC_SUBST(strip_ekg, "") AC_SUBST(strip_ioctld, "") AC_SUBST(ioctld, "") AC_SUBST(install_ioctld, "") AC_SUBST(ekg, "") AC_SUBST(install_ekg, "") AC_SUBST(clean_ekg, "") AC_SUBST(distclean_ekg, "") AC_SUBST(uninstall_ekg, "") AC_SUBST(dep_ekg, "") AC_SUBST(make_ekgwap, "") AC_SUBST(install_ekgwap, "") dnl dnl Zaczynamy testy... dnl AC_PROG_CC if test "$GCC"; then CFLAGS="$CFLAGS -Wall" dnl echo "Whoa!, GNU CC, -Wall" fi AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_C_CONST AC_PATH_PROG(GMAKE, gmake, no) if test "x$GMAKE" = "xno"; then AC_PATH_PROG(MAKE, make, no) if test "x$MAKE" = "xno"; then AC_MSG_ERROR([make ]) fi else MAKE="$GMAKE" fi AC_CHECK_TOOL(AR, ar, no) if test "x$AR" = "xno"; then AC_MSG_ERROR([ar ]) fi AC_CHECK_TOOL(STRIP, strip, :) dnl dnl Wygląda na związane z libgadu, ale jest w simlite.c... dnl dnl AC_NEED_STDINT_H dnl if test "x$STDINT_H" = "x"; then dnl cp stdint.h lib/libgadu-stdint.h dnl STDINT_H=libgadu-stdint.h dnl fi dnl SunOS AC_CHECK_LIB(nsl, t_accept, LIBS="$LIBS -lnsl") AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket") dnl BeOS AC_ARG_WITH(bind, [ --without-bind Disable linking with libbind when found]) if test "x$with_bind" != "xno"; then AC_CHECK_LIB(bind, __inet_addr, LIBS="$LIBS -lbind") fi dnl inet_pton AC_CHECK_FUNCS(inet_pton) AC_ARG_ENABLE(debug, [ --disable-debug Compile without debugging support Optional ekg Features:]) if test "x$enable_debug" = "xno"; then AC_MSG_WARN([--disable-debug is obsolete.]) fi dnl if test "x$enable_debug" = "xno"; then dnl CFLAGS="$CFLAGS -DGG_DEBUG_DISABLE" dnl strip_ekg="strip-ekg" dnl strip_ioctld="strip-ioctld" dnl else dnl CFLAGS="$CFLAGS -g" dnl fi dnl dnl Sprawdzamy OpenSSL dnl AC_CHECK_OPENSSL AC_ARG_ENABLE(openssl, [ --enable-openssl Enable OpenSSL support]) if test "x$have_openssl" = "xyes"; then OBJS="$OBJS simlite.o" LDFLAGS="$OPENSSL_LIBS $LDFLAGS" CFLAGS="$CFLAGS $OPENSSL_INCLUDES" fi dnl dirname - get rid of libgen AC_CHECK_HEADERS(libgen.h) AC_CHECK_FUNC(dirname, , [OBJS="$OBJS ../compat/dirname.o"]) dnl sprawdzamy, czy system ma getopt_long AC_CHECK_FUNC(getopt_long, , [OBJS="$OBJS ../compat/getopt.o ../compat/getopt1.o"; CFLAGS="-I../compat $CFLAGS"]) dnl na SunOSach nie ma scandir() AC_CHECK_FUNCS(scandir, , [OBJS="$OBJS ../compat/scandir.o"]) dnl setenv dla pythona AC_CHECK_FUNCS(setenv) dnl strlcat/strlcpy wiele systemów nie posiada AC_CHECK_FUNCS(strlcat, , [OBJS="$OBJS ../compat/strlcat.o"; IOCTLD_OBJS="$IOCTLD_OBJS ../compat/strlcat.o"]) AC_CHECK_FUNCS(strlcpy, , [OBJS="$OBJS ../compat/strlcpy.o"; IOCTLD_OBJS="$IOCTLD_OBJS ../compat/strlcpy.o"]) dnl utimes do sprawdzania poczty AC_CHECK_FUNCS(utimes) dnl mkstemp do zapisywania tokenów przy braku libjpeg AC_CHECK_FUNCS(mkstemp) dnl strcoll() do sortowania zgodnie z localami AC_CHECK_HEADERS(locale.h) AC_CHECK_FUNCS(setlocale) AC_CHECK_FUNCS(strcoll) dnl regexpy AC_CHECK_HEADERS(regex.h) dnl execinfo AC_CHECK_HEADERS(execinfo.h) AC_CHECK_FUNCS(backtrace) dnl libgadu AC_CHECK_LIB(gadu, gg_login, LIBS="$LIBS -lgadu", AC_MSG_ERROR([You have to install libgadu. Please see docs/libgadu.txt]) ) AC_CHECK_FUNCS(inet_pton) AC_ARG_ENABLE(ui-readline, [ --enable-ui-readline Enable readline UI]) AC_ARG_ENABLE(ui-gtk, [ --enable-ui-gtk Enable gtk UI]) AC_ARG_ENABLE(force-ncurses, [ --disable-force-ncurses Force use of ncurses UI]) AC_ARG_ENABLE(ui-ncurses, [ --disable-ui-ncurses Disable ncurses UI]) if test "x$enable_ui_ncurses" != "xno"; then AC_DEFINE(WITH_UI_NCURSES, 1, [define if you want ui-ncurses]) OBJS="$OBJS ui-ncurses.o" ui_ncurses_enabled=yes ui_ncurses_default=yes fi dnl dnl Jeśli nie chcemy ncurses, budujemy readline. dnl if test "x$enable_ui_ncurses" = "xno" -a "x$enable_ui_readline" != "xno"; then enable_ui_readline=yes fi if test "x$enable_ui_readline" = "xyes"; then AC_DEFINE(WITH_UI_READLINE, 1, [define if you want ui-readline]) OBJS="$OBJS ui-readline.o" ui_readline_enabled=yes ui_ncurses_default=no ui_readline_default=yes fi if test "x$enable_ui_readline" = "xyes" -a "x$enable_force_ncurses" = "xyes"; then AC_DEFINE(WITH_FORCE_NCURSES, 1, [define if you want ui-ncurses as default]) ui_ncurses_default=yes ui_readline_default=no fi if test "x$enable_ui_ncurses" != "xno"; then AC_CHECK_NCURSES if test "x$have_ncurses" = "x"; then AC_MSG_ERROR([You need ncurses and ncurses-devel packages.]) fi LDFLAGS="$LDFLAGS $CURSES_LIBS" CFLAGS="$CFLAGS $CURSES_INCLUDES" echo "CURSES_INCLUDES=$CURSES_INCLUDES" fi if test "x$enable_ui_gtk" != "xno"; then AC_CHECK_GTK2([], [have_gtk="yes"], [have_gtk=x"no"], []) if test "x$have_gtk" = "xyes"; then AC_DEFINE(WITH_UI_GTK, 1, [define if you want ui-gtk]) OBJS="$OBJS ui-gtk.o ui-gtk-maingui.o ui-gtk-xtext.o ui-gtk-chanview.o ui-gtk-palette.o ui-gtk-bindings.o" LDFLAGS="$LDFLAGS $GTK_LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" fi fi AC_ARG_WITH(termcap, [ --without-termcap Used to force ncurses for readline]) if test "x$enable_ui_readline" = "xyes"; then if test "x$with_termcap" = "xno"; then TERMCAP_LIB="" else AC_CHECK_LIB(termcap, tgetent, [TERMCAP_LIB="-ltermcap"]) LDFLAGS="$LDFLAGS $TERMCAP_LIB" fi if test "x$TERMCAP_LIB" = "x" -a "x$CURSES_LIBS" = "x"; then AC_CHECK_NCURSES LDFLAGS="$LDFLAGS $CURSES_LIBS" CFLAGS="$CFLAGS $CURSES_INCLUDES" fi AC_CHECK_READLINE if test "x$READLINE_LIBS" = "x"; then AC_MSG_ERROR([You need both readline and readline-devel packages.]) fi LDFLAGS="$READLINE_LIBS $LDFLAGS" CFLAGS="$CFLAGS $READLINE_INCLUDES" AC_CHECK_FUNCS([rl_set_prompt rl_filename_completion_function rl_get_screen_size rl_set_key rl_bind_key_in_map]) fi dnl dnl Sprawdzamy libgsm.so, i dnl AC_ARG_WITH(libgsm, [ --without-libgsm Compile without GSM support]) if test "x$with_libgsm" != "xno"; then AC_CHECK_LIB(gsm, gsm_decode, [ AC_CHECK_HEADERS(gsm.h, [ have_gsm_h=yes ], [ AC_CHECK_HEADERS(gsm/gsm.h, [ have_gsm_h=yes CFLAGS="$CFLAGS -I/usr/include/gsm" ]) ]) ]) if test "x$have_gsm_h" = "xyes"; then AC_CHECK_HEADERS(linux/soundcard.h, [ AC_DEFINE(HAVE_VOIP, 1, [define if you want VOIP support]) LDFLAGS="-lgsm $LDFLAGS" OBJS="$OBJS voice.o" ]) fi fi dnl dnl Sprawdzamy libungif.so i dnl AC_ARG_WITH(libungif, [ --without-libungif Compile without GIF token support]) if test "x$with_libungif" != "xno"; then AC_CHECK_LIB(ungif, DGifSlurp, [ AC_CHECK_HEADERS(gif_lib.h, [ AC_DEFINE(HAVE_LIBUNGIF, 1, [define if you have libungif]) LDFLAGS="-lungif $LDFLAGS" have_libungif=yes ]) ]) fi dnl dnl Sprawdzamy libjpeg.so i dnl AC_ARG_WITH(libjpeg, [ --without-libjpeg Compile without JPEG token support]) if test "x$with_libjpeg" != "xno"; then AC_CHECK_LIB(jpeg, jpeg_start_decompress, [ AC_CHECK_HEADERS(jpeglib.h, [ AC_DEFINE(HAVE_LIBJPEG, 1, [define if you have libjpeg]) LDFLAGS="-ljpeg $LDFLAGS" have_libjpeg=yes ]) ]) fi dnl dnl Sprawdzamy Pythona dnl AC_CHECK_PYTHON if test "x$have_python" = "xyes"; then OBJS="$OBJS python.o" LDFLAGS="$PYTHON_LIBS $LDFLAGS" CFLAGS="$CFLAGS $PYTHON_INCLUDES" fi dnl dnl Sprawdzamy libz.so, dnl AC_ARG_WITH(zlib, [ --without-zlib Compile without zlib (compressed logs)]) if test "x$with_zlib" != "xno"; then AC_CHECK_LIB(z, gzopen, [ AC_CHECK_HEADERS(zlib.h, [ AC_DEFINE(HAVE_ZLIB, 1, [define if you want compressed logs]) LDFLAGS="-lz $LDFLAGS" have_zlib=yes ]) ]) fi dnl dnl Sprawdzamy, czy użytkownik chce RTG dnl AC_ARG_ENABLE(wap, [ --enable-wap Compile WAP gateway]) if test "x$enable_wap" = "xyes"; then if test -d ekgwap; then make_ekgwap="make-ekgwap" install_ekgwap="install-ekgwap" AC_DEFINE(WITH_WAP, 1, [define if you want WAP support]) else AC_MSG_ERROR([You have to download RTG source code from http://www.comm.pl/~serek/ekgwap/]) fi fi dnl dnl Sprawdzamy, czy użytkownik chce aspell dnl AC_ARG_ENABLE(aspell, [ --enable-aspell Enable aspell support]) if test "x$enable_aspell" = "xyes"; then AC_CHECK_HEADERS(aspell.h, [ have_aspell_includes=yes ]) if test "x$have_aspell_includes" = "xyes"; then AC_CHECK_LIB(aspell, new_aspell_config, [ have_aspell_libs=yes ]) if test "x$have_aspell_libs" = "xyes"; then if test "x$ui_ncurses_default" = "xyes"; then AC_DEFINE(WITH_ASPELL, 1, [define if you want aspell support]) LDFLAGS="$LDFLAGS -laspell" fi else enable_aspell=no fi else enable_aspell=no fi fi dnl dnl Sprawdzamy ioctld dnl AC_ARG_ENABLE(ioctld, [ --enable-ioctld Compile ioctld]) if test "x$enable_ioctld" = "xyes"; then AC_CHECK_HEADERS(linux/kd.h, [ have_ioctld_includes=yes ], [ AC_CHECK_HEADERS(sys/kbio.h, [ have_ioctld_includes=yes ]) ]) if test "x$have_ioctld_includes" = "xyes"; then CFLAGS="$CFLAGS -DWITH_IOCTLD -DIOCTLD_PATH=\\\"${libexecdir}/ioctld\\\"" ioctld="ioctld" install_ioctld="install-ioctld" fi fi dnl dnl Wszystkie testy należy dodawać POWYŻEJ testu ioctld, ponieważ w przypadku dnl jego powodzenia zawartość CFLAGS skutecznie blokuje działanie gcc dnl odpalanego przez ./configure dnl lgadu="-lgadu" ekg="ekg" install_ekg="install-ekg" clean_ekg="clean-ekg" distclean_ekg="distclean-ekg" uninstall_ekg="uninstall-ekg" dep_ekg="dep-ekg" AC_CONFIG_FILES(src/Makefile) dnl AC_CONFIG_FILES(Makefile examples/Makefile) AC_OUTPUT echo echo "configured options:" dnl if test "x$have_openssl" = "xyes"; then echo " - openssl: enabled" else echo " - openssl: disabled" fi if test "x$have_ioctld_includes" = "xyes"; then echo " - ioctld: enabled" else echo " - ioctld: disabled" fi if test "x$have_python" = "xyes"; then echo " - python: enabled" else echo " - python: disabled" fi if test "x$have_zlib" = "xyes"; then echo " - zlib: enabled" else echo " - zlib: disabled" fi if test "x$have_libungif" = "xyes"; then echo " - libungif: enabled" else echo " - libungif: disabled" fi if test "x$have_libjpeg" = "xyes"; then echo " - libjpeg: enabled" else echo " - libjpeg: disabled" fi if test "x$ui_readline_enabled" = "xyes"; then if test "x$ui_readline_default" = "xyes"; then echo " - ui-readline: enabled (default)" else echo " - ui-readline: enabled" fi else echo " - ui-readline: disabled" fi if test "x$ui_ncurses_enabled" = "xyes"; then if test "x$ui_ncurses_default" = "xyes"; then echo " - ui-ncurses: enabled (default)" else echo " - ui-ncurses: enabled" fi else echo " - ui-ncurses: disabled" fi if test "x$have_gtk" = "xyes"; then echo " - ui-gtk: enabled" else echo " - ui-gtk: disabled" fi if test "x$enable_wap" = "xyes"; then echo " - rtg: enabled" fi if test "x$enable_aspell" = "xyes"; then if test "x$ui_ncurses_default" = "xyes"; then echo " - aspell: enabled" else echo " - aspell: wanted, but it's not avaiable without ncurses" fi else echo " - aspell: disabled" fi echo dnl ekg-1.9~pre+r2855/contrib/000077500000000000000000000000001174410337000152575ustar00rootroot00000000000000ekg-1.9~pre+r2855/contrib/Auto_Make_EKG000066400000000000000000000053341174410337000175420ustar00rootroot00000000000000#!/bin/bash # Skrypt do automatycznego sprawdzania czy jest nowa wersja ekg # Jezeli jest to sciaga, kompiluje i instaluje # Raport przychodzi na maila # Rev. 0.1 # (C) by Tomasz T. Ciaszczyk KAT="/usr/local/share/AutoEKG" MAILTO="root" ## Ponizej juz nic nie zmieniaj! URL="http://ekg.chmurka.net/ekg-current.tar.gz" # Odznaczamy zmienne bo nie potrafil poprawnie wyciagnac daty LC_NUMERIC="POSIX" LC_TIME="POSIX" unset LC_ALL LANG EKGCheckDir() { # Sprawdzamy czy istnieje katalog [ -d $KAT ] || mkdir -p -m 755 $KAT ; cd $KAT # Odznaczamy flage [ -f ekg-last_tgz.flg ] || touch -t 01010000 ekg-last_tgz.flg } EKGDownload() { cd $KAT # Tworzymi znacznik [ -f ekg-current.tar.gz ] && touch -r ekg-current.tar.gz ekg-last_tgz.flg wget --proxy=off --cache=off --timestamping --tries=3 --output-file=/dev/null $URL 2>&1 # Jezeli jest to samo to wychodzimy [ ekg-current.tar.gz -nt ekg-last_tgz.flg ] || exit } EKGMake() { cd $KAT DATAPLIKU=`ls -l ekg-current.tar.gz --full-time | awk '{print $7" "$8" "$9" "$10}'` DATAPLIKU=`date -d"$DATAPLIKU" +%Y%m%d` # Interesuje nas jeden plik, aby z niego wyciagnac co sie zmienilo tar xzf ekg-current.tar.gz ./ekg-$DATAPLIKU/ChangeLog LAST=`head -100 ./ekg-$DATAPLIKU/ChangeLog | grep -n "\/\/" | awk -F":" '{print $1}' | head -2 | tail -1` LAST=`expr $LAST - 1` head -$LAST ./ekg-$DATAPLIKU/ChangeLog echo "## 1/5 ** Kasowanie starego programu" rm -rf ./ekg-200* 2>&1 ; tar xzvf ekg-current.tar.gz 2>&1 [ `id -u` == 0 ] && chown -R 0.0 ekg-$DATAPLIKU echo "## 2/5 ** Kompilowanie nowej wersji" cd ./ekg-$DATAPLIKU ; ./configure 2>&1 ; cd .. cd ./ekg-$DATAPLIKU ; make -k 2>&1 ; cd .. if [ ! -f ekg-$DATAPLIKU/src/ekg ] then echo "BLAD!!!! Brak pliku ekg-$DATAPLIKU/src/ekg. Przerywam" exit 1 fi touch ekg-new_version.flg echo "## 3/5 ** Stripowanie" /bin/ls -lo ./ekg-$DATAPLIKU/src/ekg strip ./ekg-$DATAPLIKU/src/ekg /bin/ls -lo ./ekg-$DATAPLIKU/src/ekg echo "## 4/5 ** Instalowanie" cd ekg-$DATAPLIKU ; make install 2>&1 ; cd .. echo "## 5/5 Koniec :) Dziekujemy za wspolny lot" } EKG_Header() { FROM=`hostname` RND=`date "+%d.%m.%Y-%T"` RND="$RND _$RANDOM" echo "Return-Path: " echo "From: \"Aktualizator EKG - v0.1\" " echo "To: $MAILTO@$FROM" #; echo "Bcc: AutoEKG@$FROM" echo "X-Mailer: TTC AutoEKG v0.1 [pl]" echo "X-Accept-Language: pl" echo "Message-ID: " echo "Subject: EKG $DATAPLIKU" echo "" ; cat $KAT/.mail.txt } EKGCheckDir ; EKGDownload ; EKGMake > $KAT/.mail.txt [ -f ekg-new_version.flg ] || ( /bin/rm -f $KAT/.mail.txt ; exit ) [ -f /usr/sbin/sendmail ] && ( EKG_Header | /usr/sbin/sendmail $MAILTO ) /bin/rm -f $KAT/ekg-new_version.flg $KAT/ekg-last_tgz.flg $KAT/.mail.txt ekg-1.9~pre+r2855/contrib/ekg_logs/000077500000000000000000000000001174410337000170515ustar00rootroot00000000000000ekg-1.9~pre+r2855/contrib/ekg_logs/Makefile000066400000000000000000000002501174410337000205060ustar00rootroot00000000000000all: parse CFLAGS ?= -O2 -s parse: parse.c gcc $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o parse parse.c `pkg-config --cflags --libs glib-2.0` # -ggdb clean: rm -f parse ekg-1.9~pre+r2855/contrib/ekg_logs/gglogi.vim000066400000000000000000000011261174410337000210360ustar00rootroot00000000000000" syntax do vim'a do przeglądania logów moją przeglądarką logów :-) " Autor: Robert Goliasz syntax on syn match Error "^\!\!\!.*$" syn match Notice "^-\!-.*$" syn match RecTime "([0-9][0-9]:\?[0-9][0-9]\(:[0-9][0-9]\)\?)" syn match Time "[0-9][0-9]:\?[0-9][0-9]\(:[0-9][0-9]\)\?" syn match From "<.*< .*$" syn match To ">.*> .*$" hi Error ctermfg=white ctermbg=red hi Notice ctermfg=white hi Time ctermfg=darkcyan hi RecTime ctermfg=darkblue hi From ctermfg=green hi To ctermfg=blue noremap q :q! map  map  set nomodifiable set readonly ekg-1.9~pre+r2855/contrib/ekg_logs/parse.c000066400000000000000000000166751174410337000203460ustar00rootroot00000000000000/* Pobiera logi ekg z stdin i wypluwa w ładnej formie na stdout Zalety: + szybki + napisany w C Wady: - trochę nieprawidłowo wyświetla linijki zawierające tekst `\n' lub `\r' (literalnie, jeśli ktoś wpisałby backslash i [rn] w treści wiadomości) - wymaga glib'a - trzeba go skompilować - autor jest debilem. Autor: Robert Goliasz */ #define FORMAT_TIME "%02d%s%02d" #define FORMAT_SEC ":%02d" #define FORMAT_FROM "<%s< " #define FORMAT_TO ">%s> " #define FORMAT_STATUS "|%s| " #define COLOR_NORM "\033[0;37m" #define COLOR_ERR "\033[0;37;41;1m" #define COLOR_NOTICE "\033[0;37;1m" #define COLOR_TIME "\033[0;36m" #define COLOR_RECTIME "\033[0;34m" #define COLOR_FROM "\033[0;32;1m" #define COLOR_TO "\033[0;34;1m" #define COLOR_STATUS "\033[0;37m" #include #include #include #include #include // zmienne określające parametry: int nodate=0,notime=0,shownick=-1,showrecd=0,justify=0,showsec=0; int showrecsec=0,nobad=0,color=0,nostatus=0,showcolon=0; char *uin=NULL, *nick=NULL; long lastdate=0; void showhelp() { fprintf(stderr, "Pobiera logi ekg z stdin i wypluwa w ładnej formie na stdout\n" "Użycie:\n\n" "t -- nie wyświetlaj w ogóle czasu\n" "d -- nie wyświetlaj zmiany dni\n" "x -- zawsze wyświetlaj ksywkę\n" "v -- nigdy nie wyświetlaj ksywki \n" " (domyślnie: wyświetlaj jeśli nie podano opcji `u' ani `n')\n" "r -- wyświetlaj czas odebrania w wiadomościach przychodzących\n" "R -- j/w i wyrównaj wiadomości wychodzące\n" "s -- wyświetlaj sekundy\n" "S -- wyświetlaj sekundy przy czasie odebrania\n" "C -- wyświetlaj dwukropek między godziną a minutą\n" "b -- nie wyświetlaj błędnych linijek (zaczynają się od !!!)\n" "a -- nie wyświetlaj zmian statusu\n" "c -- wyświetlaj kolorki\n" "h -- this help screen\n" "u UIN -- pokazuj tylko wiadomości od/do UIN\n" "n NICK -- pokazuj tylko wiadomości od/do NICKa\n\n" "można poprzedzić `-', można łączyć lub nie, `u' lub `n' powinny być\n" "na końcu i nie powinny występować razem\n"); exit(1); } void fatal(char *s) { perror(s); fprintf(stderr,"Aby uzyskać pomoc użyj opcji -h\n"); exit(2); } void set_params(int argc, char **argv) // moje własne, może nie działać w 100% przypadków { int i; for(i=1;(i=argc) fatal("Za mało/złe parametry"); uin=argv[i+1]; break; case 'n': if(i+1>=argc) fatal("Za mało/złe parametry"); nick=argv[i+1]; break; } } } if(shownick==-1) { if(uin || nick) shownick=0; else shownick=1; } } // notime, showrecd, justify, showsec, showrecsec void print_time(time_t sent, time_t recd) { struct tm *tim; long date; tim=localtime(&sent); if(!nodate) { date=(tim->tm_year)*1000+tim->tm_yday; if(date!=lastdate) { if(color) printf(COLOR_NOTICE); printf("-!- Dzień %02d-%02d-%04d\n", tim->tm_mday,tim->tm_mon+1,tim->tm_year+1900); lastdate=date; } } if(!notime) { // czas wysłania if(color) printf(COLOR_TIME); printf(FORMAT_TIME, tim->tm_hour, showcolon ? ":" : "", tim->tm_min); if(showsec) printf(FORMAT_SEC,tim->tm_sec); printf(" "); // czas odbioru if(recd && showrecd) { if(color) printf(COLOR_RECTIME); tim=localtime(&recd); printf("("FORMAT_TIME, tim->tm_hour, showcolon ? ":" : "", tim->tm_min); if(showrecsec) printf(FORMAT_SEC,tim->tm_sec); printf(") "); } else if(justify) { printf(" "); if(showrecsec) printf(" "); if(showcolon) printf(" "); } } } int check_line(char *u, char *n) { if(uin && strcmp(uin,u)) return 0; if(nick && strcmp(nick,n)) return 0; return 1; } // przerabia linijkę żeby nie zawierała `\', kod jest do bani, ale chyba działa char *reformat(char *a, int part, char chr) { static char buf[300]; int i,len; // usuń początkowe " if(!part && a[0]=='"') strcpy(buf,a+1); else strcpy(buf,a); // zamień \" na " // zamień \r\n na << // zamień \\ na \ . len=strlen(buf); for(i=len-2;i>=0;i--) { if(buf[i]=='\\') { switch(buf[i+1]) { case '"': buf[i]='"'; break; case '\'': buf[i]='\''; break; case 'n': buf[i]=chr; buf[i+1]=' '; continue; break; case 'r': buf[i]='\n'; buf[i+1]=chr; continue; break; } memmove(buf+i+1,buf+i+2,strlen(buf+i+2)+1); } } // usuń końcowe " if( buf[strlen(buf)-1]=='\n' && buf[strlen(buf)-2]=='"') { buf[strlen(buf)-2]='\n'; buf[strlen(buf)-1]=0; } return buf; } void process_line() { char linebuf[255]; // zakładam że nagłówki nie przekraczają 249 znaków... int printed=1,reformatted=0; char chr; if(!fgets(linebuf,250,stdin)) return; if( !strncmp(linebuf,"msgrecv", 7) || !strncmp(linebuf,"chatrecv",8) ) { char **a; char *l; chr='<'; a=g_strsplit(linebuf,",",6); l=a[5]; if(a[5][0]=='"') { reformatted=1; l=reformat(a[5],0,chr); } if(check_line(a[1],a[2])) { print_time(atol(a[3]), atol(a[4])); if(color) printf(COLOR_FROM); printf(FORMAT_FROM"%s",shownick?(a[2][0]?a[2]:a[1]):"",l); } else printed=0; g_strfreev(a); } else if( !strncmp(linebuf,"msgsend", 7) || !strncmp(linebuf,"chatsend",8) ) { char **a; char *l; chr='>'; a=g_strsplit(linebuf,",",5); l=a[4]; if(a[4][0]=='"') { reformatted=1; l=reformat(a[4],0,chr); } if(check_line(a[1],a[2])) { print_time(atol(a[3]),0); if(color) printf(COLOR_TO); printf(FORMAT_TO"%s",shownick?(a[2][0]?a[2]:a[1]):"",l); } else printed=0; g_strfreev(a); } else if(!strncmp(linebuf,"status",6)) { char **a; char *l; chr='|'; a=g_strsplit(linebuf,",",7); l=a[6]; if(l && l[0]=='"') { reformatted=1; l=reformat(l,0,chr); } if(check_line(a[1],a[2]) && !nostatus) { print_time(atol(a[4]),0); if(color) printf(COLOR_STATUS); printf(FORMAT_STATUS"%s",shownick?(a[2][0]?a[2]:a[1]):"",a[5]); if(l) printf(": %s",l); } else printed=0; g_strfreev(a); } else { if(!nobad) { if(color) printf(COLOR_ERR); printf("!!! %s",linebuf); // nieznana linijka } else printed=0; } // linijki dłuższe niż 250 znaków (jeśli printed) while(strlen(linebuf)==249 && linebuf[248]!='\n') // [249] będzie zerem { fgets(linebuf,250,stdin); if(printed) { printf("%s",reformatted?reformat(linebuf,1,chr):linebuf); } } } int main(int argc, char **argv) { set_params(argc,argv); if(color) printf(COLOR_NOTICE); if(uin) printf("-!- Rozmowa z UIN %s\n",uin); if(nick) printf("-!- Rozmowa z %s\n",nick); while(!feof(stdin)) process_line(); if(color) printf(COLOR_NORM); return 0; } ekg-1.9~pre+r2855/contrib/ekgh000077500000000000000000000023551174410337000161300ustar00rootroot00000000000000#!/bin/bash # w ~/.gg/config: # log_path na ~/.gg/history # log 2 if test -z $1; then echo "Użycie: `basename $0` [nick/uin] [liczba linii (def. 20)]" exit 0 else #Kogo chcemy oglądać if [ -f $HOME/.gg/history/$1 ]; then HISTFILE=$HOME/.gg/history/$1; #jeśli podamy numerek fi for i in `ls $HOME/.gg/history/`; do if [ $(tail -n 1 $HOME/.gg/history/$i | cut -d "," -f 3 | grep -i "$1") ]; then HISTFILE=$HOME/.gg/history/$i; #jeśli podamy nick fi done fi if test -z $HISTFILE; then echo "Nie ma takiego numeru/nick-a" exit 0 fi #Ile linii historii if test -z $2; then ILELINII=20 else ILELINII=$2 fi #Żeby się cudzysłowy, przecinki, oraz \r \n dobrze wyświetlały... tail -n $ILELINII $HISTFILE | sed -e 's/\\r/\\\\r/g; s/\\n/\\\\n/g; s/,"/,/; s/"$//; s/*/"*"/g' | \ while read linia; do DATA_S=$(echo $linia | cut -d "," -f4 ) DATA=$(date -d "1970-01-01 `echo $DATA_S` sec UTC" +"%Y-%m-%d %T") #Moje bredzenie if [ "$(echo $linia | cut -d "," -f1)" = "chatsend" ]; then WYPOWIEDZ=$(echo $linia | cut -d "," -f 5-) echo -e "$DATA Ja:\n $WYPOWIEDZ" #A tu nie moje else WYPOWIEDZ=$(echo $linia | cut -d "," -f 6-) NICK=$(echo $linia | cut -d "," -f 3) echo -e "$DATA $NICK:\n $WYPOWIEDZ" fi done ekg-1.9~pre+r2855/contrib/ekglog.pl000077500000000000000000000124171174410337000170740ustar00rootroot00000000000000#!/usr/bin/perl -w # ekglog.pl - log formatter for EKG # by Michal Miszewski # # version 0.2 (06.08.2003) # + support for logged sms # + some modifications of parsing hyperlinks # + e-mail addresses parsing # + corrected html dtd header # Grzesiek Kusnierz : # + leading zero for time # + fixed parsing hyperlinks # Robert Osowiecki : # + corrected '&' with '>' (htmlize) # # version 0.1 (18.06.2003) # first published version # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. use Getopt::Long; $ver = 0.2; $mynick = "Ja"; sub fmttime { my $time = ""; my $in = shift; @tm = gmtime $in if ($in ne ""); $tm[3] = "0".$tm[3] if length($tm[3]) == 1; $tm[4]++; $tm[4] = "0".$tm[4] if length($tm[4]) == 1; $tm[2] = "0".$tm[2] if length($tm[2]) == 1; $tm[1] = "0".$tm[1] if length($tm[1]) == 1; $time = "$tm[3]-$tm[4]-".(1900 + $tm[5]) if (!$nodate); $time = $time." " if (!($nodate) && !($notime)); $time = $time."$tm[2]:$tm[1]" if (!$notime); return $time; } sub htmlize { my $ln = shift; $ln =~ s/&/&/g; $ln =~ s/\>/>/g; $ln =~ s/\$1\<\/a\>/gi; $ln =~ s/((\_|\-|\d|\w|\.)+\@(\_|\-|\d|\w|\.)+)/$1\<\/a\>/gi; $ln =~ s/[^\\]\\n/
/g; $ln =~ s/[^\\]\\r//g; $ln =~ s/\\([^\\])/$1/g; $ln =~ s/\\\\/\\/g; return $ln; } sub txtize { my $ln = shift; $ln =~ s/[^\\]\\n/\n/g; $ln =~ s/[^\\]\\r//g; $ln =~ s/\\([^\\])/$1/g; $ln =~ s/\\\\/\\/g; return $ln; } $notime = 0; $nodate = 0; GetOptions('text|x' => \$ptext, 'nohdrs|n' => \$nohdrs, 'mynum|m=i' => \$mynum, 'mynick|y=s' => \$mynick, 'nocss|c' => \$nocss, 'help|h' => \$help, 'nodate|d' => \$nodate, 'notime|t' => \$notime); if ($help) { print "ekglog version $ver by Michał Miszewski \n"; print "Użycie: $0 [-hxndtcmy] [pliki...]\n"; print " -h, --help\t\twyświetl ten tekst pomocy\n"; print " -x, --text\t\tczysty tekst na wyjściu (bez HTML)\n"; print " -n, --nohdrs\t\tpomiń nagłówki HTML\n"; print " -d, --nodate\t\tpomiń datowniki\n"; print " -t, --notime\t\tpomiń znaczniki czasu\n"; print " -c, --nocss\t\tpomiń styl CSS w kodzie HTML\n"; print " -m, --mynum=NUM\ttwój numer GG\n"; print " -y, --mynick=NUM\ttwój nick (domyślnie: $mynick)\n"; exit 1; } if (!$nohdrs and !$ptext) { print ' log '; print ' ' if !$nocss; print '
'; } while () { chomp; $text = ''; if (m/^(chat|msg)(\w+)/) { $sent = ''; if ("$2" eq 'recv') { @ln = split /,/, $_, 6; $sent = fmttime($ln[4]); $sent = " ($sent)" if ($sent ne ""); if (m/\"/) { $text = substr $ln[5], 1, -1 } else { $text = $ln[5] }; $nick = $ln[2]; $num = "/".$ln[1]; } if ("$2" eq 'send') { @ln = split /,/, $_, 5; if (m/\"/) { $text = substr $ln[4], 1, -1 } else { $text = $ln[4] }; $nick = $mynick; if ($mynum) { $num = "/".$mynum } else { $num = "" } } $time = (fmttime($ln[3]).$sent); $time = $time." " if ($time ne ""); if ($ptext) { $text = txtize $text; print "$time$nick$num\n $text\n\n" } else { $text = htmlize $text; print "
$time$nick$num
\n
$text
\n"; }; } if (m/^smssend/) { @ln = split /,/, $_, 4; if (m/\"/) { $text = substr $ln[3], 1, -1 } else { $text = $ln[3] }; $nick = $ln[1]; $time = fmttime($ln[2]); if ($ptext) { $text = txtize $text; print "$time SMS -> $nick\n $text\n\n" } else { $text = htmlize $text; print "
$time SMS -> $nick
\n
$text
\n"; }; } if (m/^status/) { @ln = split /,/, $_, 7; if (m/\"/) { $text = substr $ln[6], 1, -1 } else { $text = $ln[6] if defined($ln[6]); }; $time = fmttime $ln[4]; $time = $time." " if ($time ne ""); my %state = ( avail => "dostępny", busy => "zajęty", invisible => "niewidoczny", notavail => "niedostępny" ); if ($text eq "") { $text = "." } else { if ($ptext) { $text = txtize $text; $text = ": ".$text } else { $text = htmlize $text; $text = ": ".$text.""; } } if ($ptext) { print "$time$ln[2]/$ln[1] jest $state{$ln[5]}$text\n\n" } else { print "
$time$ln[2]/$ln[1] jest $state{$ln[5]}$text
\n" } } } print "
\n\n\n\n" if (!$nohdrs and !$ptext); ekg-1.9~pre+r2855/contrib/ekgnv.sh000077500000000000000000000067511174410337000167410ustar00rootroot00000000000000#!/bin/bash # EKG new version by drJojo # # -c || --check Sprawdź czy jest nowsza wersja. # -g || --get Sprawdź czy jest nowsza wersja i ją ściągnij. # -i || --install Sprawdź czy jest nowsza wersją, ściągnij ją i zainstaluj. # # Zmienne dla ~/.ekgnv : # WGET= ścieżka do wget'a # EKGTMP= gdzie zostanie utworzony podkatalog na pliki tymaczasowe # EKGWWW= adres strony ekg. # EKGCONF= co ma podawać do configure gdy automatycznie budujesz ekg # LASTEKG= ostatnia zainstalowana werja ekg function options { echo "EKG new version by drJojo ekgnv.sh -c || -g || -i -c || --check Sprawdź czy jest nowsza wersja. -g || --get Sprawdź czy jest nowsza wersja i ją ściągnij. -i || --install Sprawdź czy jest nowsza wersją, \ ściągnij ją i zainstaluj." exit 1 } # Czy jest plik z ustawieniami, jeżeli nie to go stwórz. if [ ! -f ~/.ekgnv ]; then \ echo -n "Brak pliku z konfiguracją. Tworze .ekgnv " touch ~/.ekgnv echo "WGET=`which wget` EKGTMP=/tmp EKGWWW=http://ekg.chmurka.net/ EKGCONF=\"--prefix=/usr --with-shared --with-ioctl\" LASTEKG=ekg-00000000" >> ~/.ekgnv echo " Gotowe!" echo fi # Wczytaj ustawienia. . ~/.ekgnv # wymyslamy bezpieczny podkatalog EKGTMPS="$EKGTMP/ekgnv-$$" mkdir "$EKGTMPS" if [ "$?" != "0" ]; then echo "Proba utworzenia katalogu tymczasowego \"$EKGTMPS\" nie powiodla sie." >&2 echo "Posprzataj \"$EKGTMP\" i sprobuj ponownie." >&2 exit 1 fi # Czy w systemie jest wget? function check_wget { if [ ! -x "$WGET" ]; then \ echo "Nie masz wget'a!"; exit 1; fi } # Pobierz strone z downloadem ekg. function get_list { check_wget echo -n "Ściągam listę wersji EKG. Poczekaj chwilę. " wget -q -P $EKGTMPS $EKGWWW/download.php # to mozna zamienic na odczytywanie pliku ktory bylby automatycznie po # twojej stronie generowany, a w ktorym bylby tylko numer najnowszej # werjsji LASTES="`grep ekg-20 $EKGTMPS/download.php | cut -d\ -f6 | \ cut -d\\" -f2 | tail -1 | sed -e s/.tar.gz//`" rm -f $EKGTMPS/download.php* echo "Gotowe!" } # Sprawdź czy jest nowsza wersja. function check_new { get_list NEW=0 # ten warunek jest wystraczalny, bo nie ma mozliwosci zeby pojawilas sie # jakas starsza wersja if [ "$LASTES" != "$LASTEKG" ]; then \ echo -n "Jest nowsza wersja $LASTES. " NEW=1 else echo "Masz najnowszą wersje EKG." exit 1 fi } # Pobierz, jeżeli jest nowsza wersja. function get_new { check_new if [ ! -z "$NEW" ]; then \ echo -n "Ściągam ją, poczekaj chwilę. " wget -q -P $EKGTMPS $EKGWWW/$LASTES.tar.gz cat ~/.ekgnv | sed -e s/$LASTEKG/$LASTES/ > ~/.ekgtmp # lub jak ktos nie ma seda to grep -v "LASTEKG" ~/.ekgnv > ~/.ekgtmp # echo "export LASTEKG=$LASTES" >> ~/.ekgtmp mv -f ~/.ekgtmp ~/.ekgnv echo "Gotowe. Plik znajduje się w $EKGTMPS/$LASTES.tar.gz" else echo fi } # Zbuduj jeżeli jest nowsza wersja. function build_new { get_new if [ ! -z "$NEW" ]; then \ echo -n "Buduje nowe EKG. Poczekaj chwilę. " ( cd $EKGTMPS ; tar -zxf $LASTES.tar.gz ; cd $LASTES ; ./configure $EKGCONF > /dev/null ; # tylko błędy będą na konsoli. make ; make install > /dev/null ; cd .. ; rm -rf $LASTES $LATES.tar.gz ; ) echo "Skończyłem. Masz już najnowszą wersję." fi } case $1 in "-c") check_new echo ;; "--check") check_new echo ;; "-g") get_new ;; "--get") get_new ;; "-i") build_new ;; "--install") build_new ;; *) options ;; esac ekg-1.9~pre+r2855/contrib/ekl2.pl000066400000000000000000000017521174410337000164560ustar00rootroot00000000000000#!/usr/bin/perl -w use POSIX; while () { chop; if (/^(chat|msg)send,/) { ($event, $uin, $nick, $time, $rest) = split /,/, $_, 5; if ($event eq "chatsend") { print "Rozmowa do " . $nick . "/" . $uin . " (" . strftime("%c", gmtime($time)) . ")\n"; } else { print "Wiadomość do " . $nick . "/" . $uin . " (" . strftime("%c", gmtime($time)) . ")\n"; } print $rest . "\n"; } else { if (/^(chat|msg)recv,/) { ($event, $uin, $nick, $time, $timesent, $rest) = split /,/, $_, 6; if ($event eq "chatrecv") { print "Rozmowa od " . $nick . "/" . $uin . " (" . strftime("%c", gmtime($time)) . "; wysłana " . strftime("%c", gmtime($timesent)) . ")\n"; } else { print "Wiadomosc od " . $nick . "/" . $uin . " (" . strftime("%c", gmtime($time)) . "; wysłana " . strftime("%c", gmtime($timesent)) . ")\n"; } print $rest . "\n"; } else { print; print "\n"; } } } ekg-1.9~pre+r2855/contrib/ekl2.sh000077500000000000000000000125561174410337000164640ustar00rootroot00000000000000#!/bin/bash # historia: # v1 (7.03.2002) grywalny skrypt, spelniajacy jako tako swoja funkcje # powstal w oczekiwaniu na pewna osobe na gg # v1.1 (8.03.2002) poprawa drukowania nietypowych znakow, np. {}%*#$ # po wyslaniu ascii-rozyczki przez gg, w logach wyraznie wymagala ona naprawy # v1.2 (9.03.2002) poprawa wydajnosci. skrypt jest juz w miare szybki # v1.3 (28.05.2002) obsluga trybow logowania 1 i 2, paprawka dotyczaca ip # obsluga wiadomosci wielolinijkowych # 1.4 (11.2002) kompletnie od nowa napisany skrypt, z kilkoma bajerkami # 1.41 (30.06.2003) poprawa wyświetlania daty, dzięki Goblinowi _ver=1.41 if [ $# -eq 0 ]; then echo "co chcesz ze mną zrobić? (użyj '$0 -h')"; exit; fi # colors Cn=$'\x1B[0;38m'; Cr=$'\x1B[0;31m'; # red Cg=$'\x1B[0;32m'; # green Ct=$'\x1B[0;33m'; # cyan Cy=$'\x1B[0;36m'; # yellow # logs dir dir="$HOME/.gg/history"; # log file fields regexps fmr="\([a-z]*recv\)"; # message received fms="\([a-z]*send\)"; # message sent fuin="\([0-9]*\)"; # uin number field fnick="\([^,]*\)"; # uin number field fdate="\([0-9]\{10\}\)"; # date field msg="\"\?\(.*[^\"]\)\"\?"; # message _getnick () { while read n; do if [ -d "$dir" ]; then buf="`sed -n "/$n/s/;.*//p" "$dir/../userlist"`"; else buf="`sed -n "/${n:-^$}/s/;.*//p" "$(dirname $dir)/userlist"`"; fi echo -e "${n}\t${buf}"; done < /dev/stdin } sessprint=1 # internal, shitty code # replacing to human readable # hmr: \1 - sent/recv, \2 - uin, \3 - nick, \4 - send date, \5 - recv date, \6 - message # hms: no recv date, \5 - message while [ $# -gt 0 ]; do case $1 in --location ) dir="$2"; shift; ;; -n | --nocolor ) unset Cn Cr Cg Ct Cy ;; -l | --sessions ) sess="yes"; if [ "x${2#?}" = "x${2#+}" ]; then sessnum="${2#+}"; shift; fi if [ "x${2#?}" = "x${2#+}" ]; then sessint="${2#+}"; shift; else sessint="60"; fi sessint="`expr $sessint \* 60`"; sessprint=0; ;; -L | --List ) list="yes"; ;; -h | --help ) cat < END exit; ;; * ) # file name fle="$1"; ;; esac shift done # logs location, setting fle variable if [ ! -d "$dir" ]; then if [ -f "$dir" -a "`basename $dir`" != "history" ]; then fle="$dir"; # if someone will set exact file else if [ -f "$dir" -a "`basename $dir`" = "history" ]; then # occurs, when log variable is set to 1 printonlynick="$fle"; fle="$dir/history"; else echo "katalog $dir nie istnieje, użyj parametru --location aby bezpośrednio określić miejsce przechowywania logów."; exit 1; fi fi fi if [ ! -f "$fle" -a -z "$list" ]; then list="hidden_yes"; fi _userslist() { if [ -d "$dir" ]; then # dir jest katalogiem ls "$dir" | _getnick else if [ -f "$dir" ]; then # dir jest plikiem zbiorczym sed -n "/^\([^,]*\),${fuin},${fnick},${fdate},/s/^\([^,]*\),${fuin},.*/\2/p" "$dir" | sort | uniq | _getnick; fi fi exit; } if [ "${list}" = "yes" ]; then _userslist; fi if [ "${list}" = "hidden_yes" ]; then if [ -d "$dir" ]; then fle="$dir/`_userslist | grep "$fle" | cut -f 1`"; else fle="$dir"; fi if [ ! -f "$fle" ]; then echo -e "Nie mogę określić pliku z logami. Upewnij się,\nże podajesz właściwą nazwę pliku/nick/numerek osoby"; exit 1; fi fi # default mode if [ -z ${hmr} ]; then hmr="\4 \3 ${Ct} \6"; hms="\4 - ${Cy} \5"; dateformat="+%H:%M %d.%m.%Y"; # see date(1) mode=1; fi disccount=0; _outputclass() { case $1 in 0 ) cat - ;; 1 ) if [ -z "${Cn}" ]; then # check if we can display colors flds="date nick msg"; else flds="date nick clr msg"; fi while read $flds; do if [ "$sess" = "yes" ]; then [ -z "$lastdate" ] && lastdate="$date"; if [ "`expr $date - $lastdate`" -gt "$sessint" ]; then let disccount++; if [ ! -z "$sessnum" -a "$sessnum" -eq "$disccount" ]||[ -z "$sessnum" ]; then echo -e "$disccount.\tRozmowa z `date --date "01/01/1970 1:0:${date}sec" "${dateformat}"`. Zaczęta przez $nick."; fi [ "$sessnum" = "$disccount" ] && sessprint=1 || sessprint=0 fi 2>/dev/null lastdate="$date"; fi if [ "$sessprint" -eq 1 ]; then echo "${clr}.--`date --date "01/01/1970 1:0:${date}sec" "${dateformat}"`- ${nick} ---- - - - "; echo "|${Cn} $msg"; echo "${clr}'--------${Cn}"; fi done < /dev/stdin ;; esac } ( sed -n "/,${printonlynick:-.*},/{ /^$fmr/ s/^${fmr},${fuin},${fnick},${fdate},${fdate},${msg}$/${hmr}/; /^$fms/ s/^${fms},${fuin},${fnick},${fdate},${msg}$/${hms}/;p;}" "$fle" ) | _outputclass $mode ekg-1.9~pre+r2855/contrib/getekg.sh000077500000000000000000000021751174410337000170710ustar00rootroot00000000000000#!/bin/bash # getekg.sh - skrypt ściągający zawsze najnowszą wersję EKG. # Autor: Arim. # Ostatnie modyfikacja: 28/05/2002 14:28 if [ "$1" == "" ]; then echo "Podaj zmienne (\"--prefix=/usr\" itp.) dla configure'a!"; exit 1; fi DIR="${TMPDIR:-${TMP:-/tmp}}/getekg-$$" if ! mkdir "$DIR"; then echo "Nie udalo sie utworzyc katalogu tymczasowego \"$DIR\"." >&2 exit 1 fi echo "Wchodzę do katalogu tymczasowego \"$DIR\"." cd "$DIR" echo -n "Ściągam najnowszą wersję." if [ ! -x "`which wget`" ]; then \ if [ ! -x "`which curl`" ]; then \ if [ ! -x "`which lynx`" ]; then \ echo "Brak możliwości ściągnięcia pliku (chyba, że pod Xami)"; exit 1; else lynx -dump http://ekg.chmurka.net/ekg-current.tar.gz | tar zxvf - fi # lynx else curl -s http://ekg.chmurka.net/ekg-current.tar.gz | tar xzf - fi #curl else wget -q -O - http://ekg.chmurka.net/ekg-current.tar.gz | tar xzf - fi #wget echo -n " Rozpakowane."; cd `ls -1 | grep ekg-` echo -n " Konfiguruję..." ./configure $* > /dev/null echo " Instaluję..." make install > /dev/null cd .. rm -r `ls -1 | grep ekg-` echo "Zrobione." ekg-1.9~pre+r2855/contrib/ioctld-client.c000066400000000000000000000122201174410337000201520ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2004 Paweł Maziarz * Wojtek Kaniewski * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #if defined (__FreeBSD__) || defined (__DragonFly__) # include #endif #ifdef sun /* Solaris */ # include # include #endif #ifdef __linux__ # include # include #endif #include #include #include #include #include #include #include /* from ictold.h stuff */ #define IOCTLD_MAX_ITEMS 50 #define IOCTLD_MAX_DELAY 2000000 #define IOCTLD_DEFAULT_DELAY 100000 #define IOCTLDNET_PORT 22004 struct action_data { int act; int value[IOCTLD_MAX_ITEMS]; int delay[IOCTLD_MAX_ITEMS]; }; enum action_type { ACT_BLINK_LEDS = 1, ACT_BEEPS_SPK = 2 }; int blink_leds(int *flag, int *delay); int beeps_spk(int *tone, int *delay); /* ioctld.h */ #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif char sock_path[PATH_MAX + 1] = ""; int blink_leds(int *flag, int *delay) { int s, fd, restore_data; fprintf(stderr, "blink_leds"); #ifdef sun if ((fd = open("/dev/kbd", O_RDONLY)) == -1) return -1; ioctl(fd, KIOCGLED, &restore_data); #else if ((fd = open("/dev/console", O_WRONLY)) == -1) fd = STDOUT_FILENO; ioctl(fd, KDGETLED, &restore_data); #endif for (s = 0; flag[s] >= 0 && s < IOCTLD_MAX_ITEMS; s++) { #ifdef sun int leds = 0; /* tak.. na sunach jest to troszkę inaczej */ if (flag[s] & 1) leds |= LED_NUM_LOCK; if (flag[s] & 2) leds |= LED_SCROLL_LOCK; if (flag[s] & 4) leds |= LED_CAPS_LOCK; ioctl(fd, KIOCSLED, &leds); #else ioctl(fd, KDSETLED, flag[s]); fprintf(stderr, " %d/%d", flag[s], delay[s]); #endif if (delay[s]) { if (delay[s] <= IOCTLD_MAX_DELAY) usleep(delay[s]); else usleep(IOCTLD_MAX_DELAY); } } #ifdef sun ioctl(fd, KIOCSLED, &restore_data); #else ioctl(fd, KDSETLED, restore_data); #endif if (fd != STDOUT_FILENO) close(fd); fprintf(stderr, "\n"); return 0; } int beeps_spk(int *tone, int *delay) { int s; #ifndef sun int fd; fprintf(stderr, "beeps_spk"); if ((fd = open("/dev/console", O_WRONLY)) == -1) fd = STDOUT_FILENO; #endif for (s = 0; tone[s] >= 0 && s < IOCTLD_MAX_ITEMS; s++) { if (tone[s]) fprintf(stderr, " %d/%d", tone[s], delay[s]); #if defined (__FreeBSD__) || defined (__DragonFly__) ioctl(fd, KIOCSOUND, 0); #endif #ifndef sun ioctl(fd, KIOCSOUND, tone[s]); #else /* żałosna namiastka... */ putchar('\a'); fflush(stdout); #endif if (delay[s]) { if (delay[s] <= IOCTLD_MAX_DELAY) usleep(delay[s]); else usleep(IOCTLD_MAX_DELAY); } } #ifndef sun ioctl(fd, KIOCSOUND, 0); if (fd != STDOUT_FILENO) close(fd); #endif fprintf(stderr, "\n"); return 0; } int main(int argc, char **argv) { int sock, port, ret; struct sockaddr_in addr; struct action_data data; struct hostent *h; in_addr_t host_addr, tmp_addr; if (argc < 2) { fprintf(stderr, "Użycie: %s [port]\n", *argv); exit(1); } if ((tmp_addr = inet_addr(argv[1])) == INADDR_NONE) { if ((h = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "Host %s nie znaleziony.\n", argv[1]); exit(1); } bcopy(*h->h_addr_list, &host_addr, sizeof(in_addr_t)); host_addr = ntohl(host_addr); } else host_addr = ntohl(tmp_addr); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Nie mogę utworzyć gniazda: %s\n", strerror(errno)); exit(1); } if (argv[2]) port = atoi(argv[2]); else port = IOCTLDNET_PORT; addr.sin_addr.s_addr = htonl(host_addr); addr.sin_port = htons(port); addr.sin_family = AF_INET; if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1) { fprintf(stderr, "Nie mogę połączyć się z %s:%d (%s)\n", argv[1], port, strerror(errno)); close(sock); exit(1); } fprintf(stderr, "Połączono.\n"); while (1) { if ((ret = read(sock, &data, sizeof(struct action_data))) == 0 || ret == -1) { if (ret == -1) perror("read()"); close(sock); exit(1); } if (data.act == ACT_BLINK_LEDS) blink_leds(data.value, data.delay); else if (data.act == ACT_BEEPS_SPK) beeps_spk(data.value, data.delay); } close(sock); exit(0); } ekg-1.9~pre+r2855/contrib/link.pl000077500000000000000000000031111174410337000165500ustar00rootroot00000000000000#!/usr/bin/perl -w ######## ## Autor: Mateusz Greszta (theKnight) ## Opis : uruchom w katalogu z logami, ## na wejscie skieruj userlist (mozna tez podac nazwe jako parametr); ## na wyjsciu masz spis polecen tworzacych powiazania symboliczne; ## Cel : utworzenie powiazan symbolicznych: ## nick (bez dziwnych znakow) -> plik z logami (nazwa == uin) ## (w nicku wszystko co nie jest litera/cyfra jest zastepowane '_' ## ale bez powtorzen -- "xx ! yy" zamienia sie na "xx_yy") ## Uwaga: dostaniesz lacza tylko do istniejacych plikow. ## polecenie 'ln -sf ...' nadpisze istniejacy plik z nazwa nicka ## (o ile taki bedzie istnial). ## nic innego nie bedzie kasowane. ## aby skrypt automatycznie uruchamal polecenia 'ln ...': ## znajdz i usun "#exec#" ponizej. ## a jak nie chcesz nic wyswietlac to zakomentuj "print;". ## PS : aha -- trzeba oczywiscie miec w systemie 'ln' ;) ######## # hash [ uin -> nick ] my %hash; while (<>) { # ominiecie 'pustych lini' next if /^\s*$/; @_ = split /;/; my ($nick, $uin) = ($_[3], $_[6]); # usuniecie \r\n (czy jakos tak) $uin =~ s/\s//g; # wszysko co nie jest /a-zA-Z0-9/ # jest zamieniane na _ (bez powtorzen) $nick =~ tr/a-zA-Z0-9_/_/cs; $hash{$uin} = $nick; $hash{"$uin.gz"} = $nick; } opendir DIR, '.'; foreach $file (readdir DIR) { if ($hash{$file}) { $_ = "ln -sf $file $hash{$file}\n" ; # tu sie laczy (: print; # tu sie pisze : #exec# `$_`; # tu sie robi :) } } ekg-1.9~pre+r2855/contrib/listmerge.c000066400000000000000000000264351174410337000174300ustar00rootroot00000000000000/* * $Id$ * * listmerge (C) 2007 Adam Wysocki */ #include #include #include #include #include #include #include extern char *optarg; extern int optind, opterr, optopt, errno; struct opt_t { int ignore_invalid; const char *outfn; const char *newline; }; struct inode_t { const char *fname; ino_t inode; }; struct userlist_entry_t { char *nick, *uin, *line; }; struct userlist_t { const char *fname; struct userlist_entry_t *entries; size_t num_entries; }; static struct opt_t opt; static void version(void) { fputs("$Id$\n", stderr); } static void fasthelp(void) { const char msg[] = "Narzędzie służy do łączenia niekompletnych list kontaktów (userlist) w ekg.\n" "\n" "Składnia: listmerge [-hvig] [-o outfile] infile1 infile2 [...]\n" "\n" "Opcje:\n" " -h: Ten ekran pomocy.\n" " -v: Wypisanie informacji o wersji.\n" " -i: Nie ignorowanie nieprawidłowych wpisów.\n" " -o: Nazwa pliku wyjściowego.\n" " -n: Zapisywanie nowych linii w postaci \\n, zamiast \\r\\n.\n" "\n" "Jeżeli plik wyjściowy nie zostanie określony, to program wyrzuci userlistę \n" "na stdout. Wpisy o powtarzających się nazwach i/lub uinach będą brane z pliku \n" "podanego wcześniej na liście poleceń.\n" "\n" "Skargi, wnioski i bugi: http://ekg.chmurka.net/kontakt.php\n"; version(); fputs(msg, stderr); } static ino_t get_inode(const char *fname) { struct stat st; if (stat(fname, &st) == -1) { fprintf(stderr, "Błąd sprawdzania statusu (stat(2)) pliku '%s': %s.\n", fname, strerror(errno)); exit(EXIT_FAILURE); } return st.st_ino; } static int inode_comparator(const void *p1, const void *p2) { const struct inode_t *i1 = p1, *i2 = p2; int rs; static int duplicate_inode_found = 0; if (!p1 && !p2) return duplicate_inode_found; rs = i1->inode - i2->inode; if (!rs) { fprintf(stderr, "Podane pliki ('%s' i '%s') to te same pliki.\n", i1->fname, i2->fname); duplicate_inode_found = 1; } return rs; } static int check_dupe_files(int ac, char * const av[]) { struct inode_t *inodes; size_t i, num = ac - optind; assert((inodes = (struct inode_t *) calloc(num, sizeof(struct inode_t)))); for (i = 0; i < num; i++) { inodes[i].fname = av[i + optind]; inodes[i].inode = get_inode(inodes[i].fname); } qsort(inodes, num, sizeof(struct inode_t), inode_comparator); free(inodes); return inode_comparator(NULL, NULL); } static void parse_opts(int ac, char * const av[]) { int done = 0; struct stat st; opt.ignore_invalid = 1; opt.outfn = NULL; opt.newline = "\r\n"; while (!done) { switch (getopt(ac, av, "hvio:n")) { case 'h': done = 2; break; case 'v': done = 3; break; case 'i': opt.ignore_invalid = 0; break; case 'o': opt.outfn = optarg; break; case 'n': opt.newline = "\n"; break; case -1: done = 1; break; default: exit(EXIT_FAILURE); } } if (done == 1 && ((unsigned) (ac - optind) < 2)) done = 2; if (done == 2 || done == 3) { if (done == 2) fasthelp(); else version(); exit(EXIT_SUCCESS); } if (opt.outfn && stat(opt.outfn, &st) != -1) { fprintf(stderr, "Podany plik wyjściowy istnieje.\n"); exit(EXIT_FAILURE); } if (check_dupe_files(ac, av)) exit(EXIT_FAILURE); } /* z ekg/compat/strlcpy.c - nie chcialem robic zaleznosci wiec * przemianowalem funkcje na xstrlcpy */ static size_t xstrlcpy(char *dst, const char *src, size_t size) { register size_t i, n = size; for (i = 0; n > 1 && src[i]; i++, n--) dst[i] = src[i]; if (n) dst[i] = 0; while (src[i]) i++; return i; } /* z ekg/src/stuff.c */ static char *read_file(FILE *f) { char buf[1024], *res = NULL; while (fgets(buf, sizeof(buf), f)) { int first = (res) ? 0 : 1; size_t new_size = ((res) ? strlen(res) : 0) + strlen(buf) + 1; assert((res = realloc(res, new_size))); if (first) *res = 0; xstrlcpy(res + strlen(res), buf, new_size - strlen(res)); if (strchr(buf, '\n')) break; } if (res && strlen(res) > 0 && res[strlen(res) - 1] == '\n') res[strlen(res) - 1] = 0; if (res && strlen(res) > 0 && res[strlen(res) - 1] == '\r') res[strlen(res) - 1] = 0; return res; } /* z ekg/src/dynstuff.c, string_t zamienione na realloc */ static char *unescape(const char *src) { int state = 0; char *buf = NULL; size_t bufsz = 0; unsigned char hex_msb = 0; #define string_append_c(ch) do { \ assert((buf = (char *) realloc(buf, bufsz + 1))); \ buf[bufsz++] = ch; \ } while (0) if (!src) return NULL; for (; *src; src++) { char ch = *src; if (state == 0) { /* normalny tekst */ /* sprawdzamy czy mamy cos po '\\', bo jezeli to ostatni * znak w stringu, to nie zostanie nigdy dodany. */ if (ch == '\\' && *(src + 1)) { state = 1; continue; } string_append_c(ch); } else if (state == 1) { /* kod ucieczki */ if (ch == 'a') ch = '\a'; else if (ch == 'b') ch = '\b'; else if (ch == 't') ch = '\t'; else if (ch == 'n') ch = '\n'; else if (ch == 'v') ch = '\v'; else if (ch == 'f') ch = '\f'; else if (ch == 'r') ch = '\r'; else if (ch == 'x' && *(src + 1) && *(src + 2)) { state = 2; continue; } else if (ch != '\\') string_append_c('\\'); /* fallback - nieznany kod */ string_append_c(ch); state = 0; } else if (state == 2) { /* pierwsza cyfra kodu szesnastkowego */ hex_msb = ch; state = 3; } else if (state == 3) { /* druga cyfra kodu szesnastkowego */ #define unhex(x) (unsigned char) ((x >= '0' && x <= '9') ? (x - '0') : \ (x >= 'A' && x <= 'F') ? (x - 'A' + 10) : \ (x >= 'a' && x <= 'f') ? (x - 'a' + 10) : 0) string_append_c(unhex(ch) | (unhex(hex_msb) << 4)); #undef unhex state = 0; } } string_append_c(0); #undef string_append_c return buf; } static size_t count_chars(const char *buf, char ch) { size_t rs = 0; while (*buf) if (*buf++ == ch) rs++; return rs; } static char *split(const char *buf, char ch, size_t num) { char *s = NULL; size_t i = 0, sz = 0; while (*buf) { if (*buf == ch) i++; else if (i == num) { assert((s = (char *) realloc(s, sz + 1))); s[sz++] = *buf; } buf++; } assert((s = (char *) realloc(s, sz + 1))); s[sz] = 0; return s; } static void add_userlist_entry(struct userlist_t *userlist, const char *line, const char *uin, const char *nick) { struct userlist_entry_t e; e.line = line ? strdup(line) : NULL; e.uin = uin ? strdup(uin) : NULL; e.nick = nick ? strdup(nick) : NULL; assert((userlist->entries = (struct userlist_entry_t *) realloc(userlist->entries, (userlist->num_entries + 1) * sizeof(struct userlist_entry_t)))); memcpy(userlist->entries + userlist->num_entries++, &e, sizeof(struct userlist_entry_t)); } static void load_userlist_entries(struct userlist_t *userlist) { FILE *fp; char *line; fp = fopen(userlist->fname, "rb"); if (!fp) { fprintf(stderr, "Nie można otworzyć pliku '%s': %s.\n", userlist->fname, strerror(errno)); exit(EXIT_FAILURE); } while ((line = read_file(fp))) { char *uin = NULL, *nick = NULL; if (line[0] == '#' || (line[0] == '/' && line[1] == '/')) { free(line); continue; } if (count_chars(line, ';') < 7) goto invalid_entry; uin = split(line, ';', 6); if (!strncasecmp(uin, "gg:", 3)) uin += 3; if (!strcmp(uin, "") || !atoi(uin)) goto invalid_entry; if ((nick = split(line, ';', 3))) { char *tmp = unescape(nick); free(nick); nick = tmp; } add_userlist_entry(userlist, line, uin, nick); goto do_continue; invalid_entry: fprintf(stderr, "Ostrzeżenie: Nieprawidłowy wpis na liście '%s': %s\n", userlist->fname, line); if (!opt.ignore_invalid) add_userlist_entry(userlist, line, NULL, NULL); do_continue: free(uin); free(nick); free(line); continue; } fclose(fp); } static size_t userlists_load(int ac, char * const av[], struct userlist_t **userlists) { struct userlist_t *u; size_t i, num = ac - optind; assert((u = (struct userlist_t *) calloc(num, sizeof(struct userlist_t)))); for (i = 0; i < num; i++) { u[i].fname = av[i + optind]; u[i].entries = NULL; u[i].num_entries = 0; load_userlist_entries(u + i); } *userlists = u; return num; } static void userlists_free(struct userlist_t *userlists, size_t num) { struct userlist_t *u = userlists; while (num--) { size_t i; for (i = 0; i < u->num_entries; i++) { free(u->entries[i].nick); free(u->entries[i].uin); free(u->entries[i].line); } free(u->entries); u++; } free(userlists); } static struct userlist_entry_t *find_dupe(struct userlist_t *userlist, const struct userlist_entry_t *src) { size_t i; const char *uin, *nick; struct userlist_entry_t *e = userlist->entries; uin = src->uin; nick = src->nick; if (uin && !strncasecmp(uin, "gg:", 3)) uin += 3; for (i = 0; i < userlist->num_entries; i++, e++) { if (uin && e->uin && *uin && *e->uin && !strcasecmp(uin, e->uin)) return e; if (nick && e->nick && *nick && *e->nick && !strcasecmp(nick, e->nick)) return e; } return NULL; } static void merge_one_userlist_entry(struct userlist_t *dst, const struct userlist_entry_t *src) { struct userlist_entry_t *found; if ((found = find_dupe(dst, src))) { fprintf(stderr, "Usunięcie wpisu '%s', bo już jest na liście jako '%s'.\n", src->line, found->line); return; } add_userlist_entry(dst, src->line, src->uin, src->nick); } static void merge_one_userlist(struct userlist_t *dst, const struct userlist_t *src) { size_t i; for (i = 0; i < src->num_entries; i++) merge_one_userlist_entry(dst, src->entries + i); } static int userlist_entry_comparator(const void *p1, const void *p2) { struct userlist_entry_t *e1 = (struct userlist_entry_t *) p1; struct userlist_entry_t *e2 = (struct userlist_entry_t *) p2; if (!e1->nick || !e2->nick) return 1; /* xxx strcoll - wpisy na wynikowej liście będą sortowane leksykograficznie * bez uwzględnienia polskich znaków - to nie ma takiego znaczenia, ekg i * tak posortuje. użycie strcoll tutaj wymagałoby dodatkowych testów przed * kompilacją przy użyciu autoconfa albo czegoś podobnego. */ return strcasecmp(e1->nick, e2->nick); } static struct userlist_t *userlists_merge(const struct userlist_t *userlists, size_t num) { size_t i; struct userlist_t *final; assert((final = (struct userlist_t *) malloc(sizeof(struct userlist_t)))); final->fname = opt.outfn; final->entries = NULL; final->num_entries = 0; for (i = 0; i < num; i++) merge_one_userlist(final, userlists + i); qsort(final->entries, final->num_entries, sizeof(struct userlist_entry_t), userlist_entry_comparator); return final; } static void save_final_list(struct userlist_t *u) { FILE *fp = stdout; size_t i; struct userlist_entry_t *e = u->entries; if (u->fname && !(fp = fopen(u->fname, "w"))) { fprintf(stderr, "Nie udało się otworzyć pliku '%s': %s.\n", u->fname, strerror(errno)); exit(EXIT_FAILURE); } for (i = 0; i < u->num_entries; i++, e++) fprintf(fp, "%s%s", e->line, opt.newline); if (u->fname) fclose(fp); } int main(int ac, char * const av[]) { struct userlist_t *userlists, *final_list; size_t userlists_num = 0; parse_opts(ac, av); userlists_num = userlists_load(ac, av, &userlists); final_list = userlists_merge(userlists, userlists_num); userlists_free(userlists, userlists_num); save_final_list(final_list); userlists_free(final_list, 1); return 0; } ekg-1.9~pre+r2855/contrib/scripts/000077500000000000000000000000001174410337000167465ustar00rootroot00000000000000ekg-1.9~pre+r2855/contrib/scripts/ekgbot-pre1.py000066400000000000000000000606611174410337000214510ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: ISO-8859-2 -*- # ekg-bot 0.1-pre1 # Copyright (C) 2003 Andrzej Lindnał # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # http://www.gnu.org/copyleft/gpl.html # # New releases: http://bot.czad.org/ # Looking for erecoder?: http://eleet.czad.org/ import ekg,re,os,string,types,random,math,base64 # Importy from urllib import * # Obsługa www from time import * # Operacje czasowe from random import Random # Random from os import * # do implementacji popen #import sys # debugowanie implementacji popen # Konfiguracja owner = twojnumer # Numer gg ownera # Check with: $ whereis path_cat = "/bin/cat" path_bot = "SCIEZKA DO PLIKU *.PY BOTA" path_wc = "/usr/bin/wc" path_uptime = "/usr/bin/uptime" path_erecoder = "/usr/local/bin/erecoder" # [ http://eleet.czad.org ] path_uname = "/bin/uname" path_fetchmail = "/usr/bin/fetchmail" path_host = "/usr/bin/host" path_free = "/usr/bin/free" path_df = "/bin/df" ################################################################# # Below is the script's source code. # # You are allowed to modify it under conditions of GNU GPL. # # If you know, what are you doing, of course. :) # ################################################################# # Poniżej jest kod źródłowy skryptu. # # Możesz go modyfikować pod warunkami GNU GPL. # # Jeśli wiesz, co robisz, oczywiście. :) # ################################################################# owner = int(owner) ver = 'ekg-bot 0.1-pre1 "qm"' wwwpage = "bot.czad.org" def handle_msg(uin, name, msgclass, text, time, secure): uin = int(uin) if len(text) == 0: ekg.command("msg %d Mógłbyś coś napisać?;)" % uin) return elif text[0] in ["!", "@"]: komenda(uin, text) elif text[0] == "?": helpf(uin, text) def komenda(uin, text): ownerz = {"private": (private, 1), "owner": (chowner, 1), "save": (saveall, 0), "add": (addnew, 2), "free": (freestats, 0), "dysk": (hddstats, 0), "refstatus": (refstatus, 0), "msg": (mesgtouin, 2), "checkurl": (ciekurl, 1), "host": (ciekhost, 1), "fetchmail": (fetchmail, 0), "reconnect": (reconnect, 0), "block": (killfile, 1), "ignore": (ignore, 1), "msgid": (googleid, 1), "invisible": (invis, 1), "unblock": (unblock, 1), "unignore": (unignore, 1), "kill": (killme, 0)} userz = {"status": (ciekstatus, 1), "uname": (uname, 0), "krot": (krot, 1), "drot": (drot, 1), "kbase": (kbase, 0), "dbase": (dbase, 0), "time": (ciektime, 0), "uptime": (uptime, 0), "kod": (ciekkod, 0), "hello": (hellou, 2), "rand": (randomik, 2), "sim": (wyslij_klucz, 0), "ile": (ile, 2), "odliczanie": (odlicz, 1), "lotto": (lottomat, 1), "zycie": (zycie, 3), "sin": (sin, 1), "cos": (cos, 1), "tg": (tg, 1), "ctg": (ctg, 1), "help": (helpuj, 0), "kmorse": (kmorse, 0), "dmorse": (dmorse, 0), "bmi": (bmi, 2) } if text[0] == "@": if uin != owner: ekg.command("msg %d Czy Ty aby na pewno jesteś właścicielem tego bota?;)" % uin) return tablica = ownerz elif text[0] == "!": tablica = userz else: return pozycja = text.find(" ") if pozycja == -1: kom = text[1:] kom = kom.lower() arg = "" else: kom = text[1:pozycja] kom = kom.lower() arg = text[pozycja+1:] try: funkcja, ilosc = tablica[kom] except: return # jesli komenda wymaga argumentow if ilosc > 0: splitarg = arg.split() args = splitarg[:ilosc] if len(splitarg) > ilosc: args.append(string.join(splitarg[ilosc:])) # jesli komenda nie wymaga argumentow elif ilosc == 0: if len(arg) > 0: args = [arg] else: args = [] # bledny wpis w liscie komend else: return try: funkcja(uin, *args) except TypeError, exc: emsg = exc.args[0] if emsg.find(funkcja.__name__ + "()") != -1: ekg.command("msg %d Zła ilość parametrów. Wpisz polecenie: ?%s" % (uin, kom)) else: ekg.command("msg %d Błąd wykonania: %s" % (uin, emsg)) return except Exception, exc: emsg = exc.args[0] ekg.command("msg %d Błąd wykonania: %s" % (uin, emsg)) return def init(): ekg.printf("generic", "Zaladowano ekg-bot %s!" % ver) ekg.command("away %s @ %s" % (ver, wwwpage)) def deinit(): ekg.printf("generic", "Usunieto ekg-bota %s!" % ver) def odliczanie(dzien, miesiac): teraz = mktime((localtime()[0],int(miesiac),int(dzien)+1,0,0,0,0,0,1))-time() if teraz < 0: teraz = mktime((localtime()[0]+1,int(miesiac),int(dzien),0,0,0,0,0,1))-time() elif teraz == 0: zostanie = 0 return int(zostanie) zostanie = teraz/86400 return int(zostanie) def lotto(ilosc_kulek, ilosc_losowanych_kulek): komora = range(1,ilosc_kulek) wylosowane = [] for x in range(ilosc_losowanych_kulek): liczba = random.choice(komora) komora.remove(liczba) wylosowane.append(liczba) wylosowane.sort() wynik = "" for x in wylosowane: wynik += "%d" % x + ", " return wynik[:-2] def czyPrzestepny(rok): przestepny = 0 if rok % 4 == 0: przestepny = 1 if rok % 100 == 0: przestepny = 0 if rok % 400 == 0: przestepny = 1 return przestepny def poprawna_data(dzien, miesiac, rok): try: dzien = int(dzien) miesiac = int(miesiac) rok = int(rok) if (dzien > 31 or dzien < 1) or (miesiac > 12 or miesiac < 1) or rok < 1900: return 0 mce = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31} przestepny = czyPrzestepny(rok) if miesiac != 2 and dzien > mce[miesiac]: return 0 if miesiac == 2 and ((przestepny and dzien > 29) or (not przestepny and dzien > 28)): return 0 return 1 except: return 0 def zycie(uin, dzien, miesiac, rok): try: dzien = int(dzien) miesiac = int(miesiac) rok = int(rok) except: ekg.command("msg %d Coś nie tak z datą, ech." % uin) return if not poprawna_data(dzien, miesiac, rok): ekg.command("msg %d Niepoprawny dzień, miesiąc lub rok. Czy to takie trudne?:)" % uin) return (y,m,d) = localtime()[:3] qmk = time()-mktime((rok,miesiac,dzien,0,0,0,0,0,1)) if rok > y: ekg.command("msg %d Niepoprawny rok..." % uin) return if qmk < 0: ekg.command("msg %d Niepoprawny dzień lub miesiąć." % uin) return if rok == y and dzien == d and miesiac == m: ekg.command("msg %d Urodziłeś się dzisiaj? Zdolny bobas." % uin) return dni = qmk/86400 lat = qmk/31556736 ekg.command("msg %d To jest już Twój %.0f dzień życia. Żyjesz już %.0f lat (%.0f sekund). %s" % (uin, dni, math.floor(lat), qmk, zodiak(dzien, miesiac))) def zodiak(dzien, miesiac): if (miesiac == 3 and dzien >= 21) or (miesiac == 4 and dzien <= 20): qmju = "Twój znak zodiaku to baran." elif (miesiac == 4 and dzien >= 21) or (miesiac == 5 and dzien <= 20): qmju = "Twój znak zodiaku to byk." elif (miesiac == 5 and dzien >= 21) or (miesiac == 6 and dzien <= 21): qmju = "Twój znak zodiaku to bliźnięta." elif (miesiac == 6 and dzien >= 22) or (miesiac == 7 and dzien <= 22): qmju = "Twój znak zodiaku to rak." elif (miesiac == 7 and dzien >= 23) or (miesiac == 8 and dzien <= 23): qmju = "Twój znak zodiaku to lew." elif (miesiac == 8 and dzien >= 24) or (miesiac == 9 and dzien <= 22): qmju = "Twój znak zodiaku to panna." elif (miesiac == 9 and dzien >= 23) or (miesiac == 10 and dzien <= 23): qmju = "Twój znak zodiaku to waga." elif (miesiac == 10 and dzien >= 24) or (miesiac == 11 and dzien <= 21): qmju = "Twój znak zodiaku to skorpion." elif (miesiac == 11 and dzien >= 23) or (miesiac == 12 and dzien <= 21): qmju = "Twój znak zodiaku to strzelec." elif (miesiac == 12 and dzien >= 22) or (miesiac == 1 and dzien <= 20): qmju = "Twój znak zodiaku to koziorożec." elif (miesiac == 1 and dzien >= 21) or (miesiac == 2 and dzien <= 19): qmju = "Twój znak zodiaku to wodnik." elif (miesiac == 2 and dzien >= 20) or (miesiac == 3 and dzien <= 20): qmju = "Twój znak zodiaku to ryby." else: qmju = " " return qmju def trygonometria(dzialanie, wartosc): dzial = int(wartosc) / 360.0 * math.pi * 2 if dzialanie == "sin": wynik = math.sin(dzial) elif dzialanie == "cos": wynik = math.cos(dzial) elif dzialanie == "tg": wynik = math.tan(dzial) elif dzialanie == "ctg": wynik = 1 / math.tan(dzial) return wynik def helpf(uin, text): if text.find(" ") == 1: ekg.command("msg %d Nie należy podawać argumentów." % uin) return pol = text[1:] helpy = {"private": "Wywołanie:\r\n@private on/off - ustawia tryb \"Tylko dla znajomych\" na bocie.", "owner": "Wywołanie:\r\n@owner on/off - ustawia tryb \"Dostępny\" na włączony lub wyłączony.", "save": "Wywołanie:\r\n@save - zapisuje i wysyła plik konfiguracyjny razem z listą kontaktów na serwer GaduGadu", "add": "Wywołanie:\r\n@add uin nazwa - dodaje numer do listy kontaktów", "free": "Wywołanie:\r\n@free - wysyła statystyki pamięci na serwerze, gdzie uruchomiony jest bot", "dysk": "Wywołanie:\r\n@df -h - wysyła statystyki dysku twardego, na którym uruchomiony jest bot", "refstatus": "Wywołanie:\r\n@refstatus - odświeża status", "msg": "Wywołanie:\r\n@msg uin treść - wysyła pod numer GaduGadu treść wiadomości", "checkurl": "Wywołanie:\r\n@checkurl adres_strony - sprawdza na jakim serwerze serwowana jest:) podana strona. UWAGA! Adres NIE MOŻE zawierać http:// ani \"/\" na końcu! np. @checkurl czad.org", "host": "Wywołanie:\r\n@host ip/host - sprawdza numer IP hosta, lub host numeru IP:)", "fetchmail": "Wywołanie:\r\n@fetchmail - wywołuje \"fetchmail\"'a, program ściągający pocztę z innych serwerów. Aby z tego skorzystać, użytkownik musi skontaktować się z administratorem lub konfigurując program wcześniej samemu.", "reconnect": "Wywołanie:\r\n@reconnect - łączy ponownie z serwerem GG", "block": "Wywołanie:\r\n@block uin - blokuje podany numer GaduGadu", "ignore": "Wywołanie:\r\n@ignore uin - ignoruje podany numer GaduGadu", "msgid": "Wywołanie:\r\n@msgid msg-id - wysyła linka, na który należy wejśc, aby przeczytać podany Message-ID (z usenetu)", "status": "Wywołanie:\r\n!status uin - sprawdza status podanego numeru GaduGadu [dane pobiera ze skryptu na stronie programu GaduGadu]", "uname": "Wywołanie:\r\n!uname - podaje system operacyjny, na jakim chodzi bot", "krot": "Wywołanie:\r\n!krot 2-23 tekst - koduje podany tekst systemem ROT. Liczba musi być z przedziału od 2 do 23", "drot": "Wywołanie:\r\n!drot 2-23 tekst - dekoduje podany tekst w systemie ROT. Liczba musi być z przedziału 2-23", "kbase": "Wywołanie:\r\n!kbase tekst - koduje podany tekst do systemu Base64", "dbase": "Wywołanie:\r\n!dbase tekst - dekoduje tekst podany w systemie Base64", "time": "Wywołanie:\r\n!time - podaje aktualną datę, godzinę i czas [letni lub zimowy]", "uptime": "Wywołanie:\r\n!uptime - podaje aktualny UpTime serwera, na którym stoi bot", "kod": "Wywołanie:\r\n!kod - podaje aktualną ilość linii kodu bota oraz ilość bajtów jaką on zajmuje", "hello": "Wywołanie:\r\n!hello uin nick - wysyła do ownera bota prośbę, o dodanie do listy kontaktów. Owner bota otrzyma wiadomość zawierającą UIN osoby wysyłającej, UIN osoby zgłaszanej i nick.", "rand": "Wywołanie:\r\n!rand liczba1 liczba2 - losuje liczbe z podanego przedziału. Pierwsza liczba musi być większa od drugiej. Liczby mogą być ujemne", "sim": "Wywołanie:\r\n!sim - wysyła pod numer klucz bota do rozmów szyfrowanych. Przydatne użytkownikom programu PowerGG + wtyczki GaduCrypt", "ile": "Wywołanie:\r\n!ile dzień miesiąc - wylicza ile pozostało dni do podanej przez użytkownika daty", "odliczanie": "Wywołanie:\r\n!odliczanie parametr - podaje ile zostało dni do ustalonego \"terminu\". Obsługiwane terminy: wakacje, rok.", "lotto": "Wywołanie:\r\n!lotto parametr - bot losuje liczby do losowań Lotto. Obsługiwane losowania: multi, duzy, express, zaklady", "zycie": "Wywołanie:\r\n!zycie dzień miesiąc rok - bot podaje informacje wykorzystując podaną datę urodzenia", "sin": "Wywołanie:\r\n!sin parametr - podaje wartość funkcji sinus dla kąta", "cos": "Wywołanie:\r\n!cos parametr - podaje wartość funkcji cosinus dla kąta", "tg": "Wywołanie:\r\n!tg parametr - podaje wartość funkcji tangens dla kąta", "ctg": "Wywołanie:\r\n!ctg parametr - podaje wartość funkcji cotangens dla kąta", "kmorse": "Wywołanie:\r\n!kmorse tekst - koduje podany tekst do alfabetu Morse'a. Tekst nie może zawierać znaków specjalnych i polskich literek.", "dmorse": "Wywołanie:\r\n!dmorse tekst - dekoduje podany alfabet Morse'a do zwykłego tekstu. Jeśli tekst nie będzie alfabetem morse'a bot odpisze tym samym tekstem.", "bmi": "Wywołanie:\r\n!bmi waga wzrost - podaje Body Mass Index. Waga musi być podana w kilogramach, wzrost w centymetrach", "help": "Wywołanie:\r\n!help - podaje wszystkie polecenia obsługiwane przez bota.", "invisible": "Wywołanie:\r\n!invisible on/off - ustawia tryb \"niewidoczny\" na bocie.", "unblock": "Wywołanie:\r\n@unblock uin - usuwa blokadę z podanego uin'u", "unignore": "Wywołanie:\r\n@unignore uin - usuwa ignorowanie z podanego uin'u", "kill": "Wywołanie:\r\n@kill - wyłącza bota razem z klientem GG"} if helpy.has_key(pol.lower()): ekg.command("msg %d %s" % (uin, helpy[pol.lower()])) else: ekg.command("msg %d Nieznane polecenie ?%s" % (uin, pol)) def private(uin, tryb): tryb = tryb.lower() if tryb == "on": ekg.command("private on") ekg.command("msg %d Zmieniono tryb \"Tylko dla znajomych\" na włączony" % uin) elif tryb == "off": ekg.command("private off") ekg.command("msg %d Zmieniono tryb \"Tylko dla znajomych\" na wyłączony" % uin) else: ekg.command("msg %d Funkcja @private przyjmuje tylko wartości \"on\" lub \"off\"" % uin) def chowner(uin, tryb): status_ref = strftime("%a, %d %b %Y %H:%M:%S %Z") tryb = tryb.lower() if tryb == "on": ekg.command("back %s @ %s" % (ver, wwwpage)) elif tryb == "off": ekg.command("away %s @ %s" % (ver, wwwpage)) else: ekg.command("msg %d Funkcja @owner przyjmuje tylko wartości \"on\" lub \"off\"" % uin) def saveall(uin): ekg.command("echo Zapisuję...") ekg.command("save") ekg.command("echo Próbuję wysłać na serwer...") ekg.command("list -P") ekg.command("msg %d Zapisano ustawienia i spróbowano je wysłać na serwer razem z listą kontaktów" % uin) # Dlaczego spróbowano? Bo nie wiadomo czy dotarły one na serwer GG. def addnew(uin, duin, nazwa): try: ekg.command("add %d %s" % (int(duin), nazwa)) ekg.command("msg %d Dodałem %s (%s) do listy kontaktów." % (uin, duin, nazwa)) except: ekg.command("msg %d Pierwszy parametr to UIN, a drugi NAZWA." % uin) def freestats(uin): free = os.popen("%s -m" % path_free).read() ekg.command("msg %d %s" % (uin, free)) def hddstats(uin): df = os.popen("%s -h" % path_df).read() ekg.command("msg %d %s" % (uin, df)) def refstatus(uin): status_ref = strftime("%a, %d %b %Y %H:%M:%S %Z") ekg.command("away %s @ %s" % (ver, wwwpage)) def mesgtouin(uin, to, tresc): try: ekg.command("msg %d %s" % (int(to), tresc)) except: ekg.command("msg %d Pierwszy parametr to UIN odbiorcy, drugi to treść." % uin) def ciekurl(uin, url): checkurl = URLopener().open(("http://%s/" % url)) ekg.command("msg %d %s" % (uin, checkurl.info().getheader('Server'))) def ciekhost(uin, host): qmer = safepopen([path_host, host]) ekg.command("msg %d %s" % (uin, qmer)) def fetchmail(uin): os.popen("%s" % path_fetchmail) ekg.command("msg %d Wywołałem fetchmaila." % uin) def reconnect(uin): ekg.disconnect("Reconnecting...") ekg.connect() ekg.command("away %s @ %s" % (ver, wwwpage)) def killfile(uin, ktos): try: ktos = int(ktos) ekg.command("block %d" % ktos) ekg.command("msg %d %d został zablokowany" % (uin, ktos)) except: ekg.command("msg %d Musisz podać parametr jako UIN do zablokowania" % uin) def unblock(uin, numer): try: numer = int(numer) ekg.command("unblock %d" % numer) ekg.command("msg %d %d został odblokowany" % (uin, numer)) except: ekg.command("msg %d Musisz podać parametr jako UIN do odblokowania" % uin) def ignore(uin, ktos): try: ktos = int(ktos) ekg.command("ignore %d" % ktos) ekg.command("msg %d %d został ignorowany" % (uin, ktos)) except: ekg.command("msg %d Musisz podać parametr jako UIN do ignorowania" % uin) def unignore(uin, numer): try: numer = int(numer) ekg.command("unignore %d" % numer) ekg.command("msg %d %d został odignorowany" % (uin, numer)) except: ekg.command("msg %d Musisz podać parametr jako UIN do odignorowania" % uin) def googleid(uin, msgid): ekg.command("msg %d Link do MessageID, który podałeś: http://groups.google.pl/groups?selm=%s" % (uin, str(msgid))) def ciekstatus(uin, kto): try: checkurl = URLopener().open(("http://www.gadu-gadu.pl/users/status.asp?id=%d&styl=2" % int(kto))) ciek = checkurl.read() if ciek == "3": sztatus = "zaraz wraca" elif ciek == "2": sztatus = "jest dostępny" elif ciek == "1": sztatus = "jest niedostępny" else: sztatus = "[błąd, nie mogę podać statusu]" ekg.command("msg %d Numer %d %s" % (uin, int(kto), sztatus)) except: ekg.command("msg %d Przydało by się jako parametr podać UIN;)" % uin) def uname(uin): ekg.command("msg %d %s" % (uin, os.popen("%s -mnrs" % path_uname).read())) def krot(uin, ile, tekst): ile = int(ile) if ile < 2 or ile > 23: ekg.command("msg %d Jako pierwszy parametr należy podać liczbę z zakresu 2-23." % uin) else: try: ekg.command("msg %d %s" % (uin, safepopen([path_erecoder, '-ear'+ile, '--', tekst]))) except: ekg.command("msg %d Jako pierwszy parametr należy podać liczbę z zakresu 2-23." % uin) def drot(uin, ile, tekst): ile = int(ile) if ile < 2 or ile > 23: ekg.command("msg %d Jako pierwszy parametr należy podać liczbę z zakresu 2 - 23." % uin) else: try: ekg.command("msg %d %s" % (uin, safepopen([path_erecoder, '-dar'+ile, '--', tekst]))) except: ekg.command("msg %d Jako pierwszy parametr należy podać liczbę z zakresu 2-23" % uin) def kbase(uin, tekst): zak = base64.encodestring(tekst) ekg.command("msg %d %s" % (uin, zak)) def dbase(uin, tekst): dek = base64.decodestring(tekst) ekg.command("msg %d %s" % (uin, dek)) def ciektime(uin): dni = {0: "poniedziałek", 1: "wtorek", 2: "środa", 3: "czwartek", 4: "piątek", 5: "sobota", 6: "niedziela"} miesiace = {1: "stycznia", 2: "luty", 3: "marca", 4: "kwietnia", 5: "maja", 6: "czerwca", 7: "lipca", 8: "sierpnia", 9: "września", 10: "października", 11: "listopada", 12: "grudnia"} czasy = {1: "letni", 2: "zimowy"} tajm = localtime() ekg.command("msg %d Dzisiaj jest %s, %d %s %d roku. Jest godzina %d:%d:%d, czas %s." % (uin, dni[tajm[6]], tajm[2], miesiace[tajm[1]], tajm[0], tajm[3], tajm[4], tajm[5], czasy[tajm[8]])) def uptime(uin): up = os.popen("%s" % path_uptime).read() inter = string.join(up.split()[1:4]) ekg.command("msg %d %s" % (uin, inter)) def ciekkod(uin): cmd = os.popen("%s %s | %s -l" % (path_cat, path_bot, path_wc)) cmd2 = os.stat("%s" % path_bot) ekg.command("msg %d Aktualnie bot posiada %s linii kodu oraz zajmuje %s bajtów." % (uin, cmd.read().replace(" ", ""), cmd2[6])) def hellou(uin, kto, nick): try: ekg.command("msg %d Ok, przyjąłem." % uin) ekg.command("msg %d Zgłosił się:\r\nUIN wysyłającego: %d\r\nUIN zgłaszanego: %d\r\nImię zgłaszanego: %s\r\n" % (owner, int(uin), int(kto), re.escape(nick))) except: ekg.command("msg %d Pierwszy musi być numer. Nie przyjąłem." % uin) def randomik(uin, p, d): if abs(int(p)) > abs(int(d)): ekg.command("msg %d Pierwsza liczba musi być mniejsza od drugiej." % uin) elif abs(int(p)) > 2147483646 or abs(int(d)) > 2147483646: ekg.command("msg %d Ciutke za duża liczba." % uin) elif int(p) == int(d): ekg.command("msg %d Wylosowana z tych samych liczb została liczba %d" % (uin, int(p))) else: a = Random() wyn = a.randint(int(p), int(d)) try: ekg.command("msg %d %d" % (uin, wyn)) except: ekg.command("msg %d Należy podać dwie LICZBY." % uin) def wyslij_klucz(uin): ekg.command("key -s %d" % uin) ekg.command("msg %d Klucz został wysłany." % uin) def ile(uin, dzien, miesiac): try: dzien = int(dzien) miesiac = int(miesiac) if not poprawna_data(dzien, miesiac, localtime()[0]): ekg.command("msg %d Fajne dni i miesiące, nie ma co." % uin) return ekg.command("msg %d Do daty %d.%d pozostało %s dni." % (uin, dzien, miesiac, odliczanie(dzien, miesiac))) except: ekg.command("msg %d Musisz podać dwie liczby:\r\npierwsza - dzień miesiąca\r\ndruga - miesiąc." % uin) def odlicz(uin, termin): try: termin = termin.lower() if termin == "wakacje": ekg.command("msg %d Do wakacji (21 czerwca) pozostało %s dni." % (uin, odliczanie(21,6))) elif termin == "rok": ekg.command("msg %d Do końca roku kalendarzowego pozostało %s dni." % (uin, odliczanie(1,1))) else: ekg.command("msg %d Nieznany parametr." % uin) except: ekg.command("msg %d Nieznany termin. Obsługiwane terminy:\r\nwakacje\r\neuropa\r\nrok" % uin) def lottomat(uin, typ): typ = typ.lower() if typ == "multi": ekg.command("msg %d Wylosowane przez komputer liczby do losowań MultiLotka to: %s" % (uin, lotto(81, 10))) elif typ == "duzy" or typ == "duży": ekg.command("msg %d Wylosowane przez komputer liczby do losowań DużegoLotka to: %s" % (uin, lotto(49, 6))) elif typ == "express" or typ == "ekspress": ekg.command("msg %d Wylosowane przez komputer licbzy do losowań ExpressLotka to: %s" % (uin, lotto(42, 5))) elif typ == "zaklady" or typ == "zakłady": ekg.command("msg %d Wylosowane przez komputer liczby do losowań Zakładów Specjalnych to: %s" % (uin, lotto(42,5))) else: ekg.command("msg %d Nieznany parametr! Parametry:\r\nmulti, duzy, express, zaklady" % uin) def sin(uin, liczba): try: ekg.command("msg %d %s" % (uin, trygonometria('sin', liczba))) except: ekg.command("msg %d Błędne wywołanie." % uin) def cos(uin, liczba): try: ekg.command("msg %d %s" % (uin, trygonometria('cos', liczba))) except: ekg.command("msg %d Błędne wywołanie." % uin) def tg(uin, liczba): try: ekg.command("msg %d %s" % (uin, trygonometria('tg', liczba))) except: ekg.command("msg %d Błędne wywołanie." % uin) def ctg(uin, liczba): try: ekg.command("msg %d %s" % (uin, trygonometria('ctg', liczba))) except: ekg.command("msg %d Błędne wywołanie." % uin) def helpuj(uin): ekg.command("""msg %d Polecenia ownera:\r\n@private, @invisible, @owner, @save, @add, @free, @dysk, @refstatus, @msg, @checkurl, @host, @fetchmail, @reconnect, @block, @ignore, @msgid.\r\nPolecenia użytkowników:\r\n!status, !uname, !krot, !drot, !kbase, !dbase, !time, !uptime, !kod, !hello, !rand, !sim, !ile, !odliczanie, !lotto, !zycie, !sin, !cos, !tg, !ctg, !kmorse, !dmorse, !bmi \r\nPomoc do każdego z poleceń można uzyskać pisząc wiadomość ?polecenie. Na przykład: ?status.\r\nAutorem tego bota jest Andrzej Lindnał""" % uin) def kmorse(uin, tekst): ekg.command("msg %d %s" % (uin, safepopen([path_erecoder, '-eam', '--', tekst]))) def dmorse(uin, tekst): ekg.command("msg %d %s" % (uin, safepopen([path_erecoder, '-dam', '--', tekst]))) def bmi(uin, masa, wzrost): try: masa = float(masa) wzrost = float(wzrost) except: ekg.command("msg %d Cyferki, cyferki:)" % uin) return if masa <= 0 or wzrost <= 0: ekg.command("msg %d Kiepsko u Ciebie z wagą..." % uin) return bmi = masa / (wzrost / 100.0) ** 2 if bmi <= 18.5: qm = "niedowagę" elif bmi > 18.5 and bmi < 25.0: qm = "normalną wagę" elif bmi >= 25.0: qm = "nadwagę" ekg.command("msg %d Twój BMI to %.2f. Masz %s." % (uin, bmi, qm)) def invis(uin, tryb): tryb = tryb.lower() if tryb == "on": ekg.command("invisible") ekg.command("msg %d Zmieniono tryb \"niewidoczny\" na włączony" % uin) elif tryb == "off": ekg.command("away") ekg.command("msg %d Zmieniono tryb \"niewidoczny\" na wyłączony" % uin) else: ekg.command("msg %d Funkcja @invisible przyjmuje tylko wartości \"on\" lub \"off\"" % uin) def killme(uin): ekg.command("msg %d Wyłączam EKG. Aby mnie ponownie włączyć, będziesz musiał zalogować się na shella niestety;))" % uin) ekg.command("quit") def safepopen(cmd): rfd, wfd = pipe() ret = fork() # child if ret == 0: close(rfd) dup2(wfd, 1) execv(cmd[0], cmd) exit(1) # parent else: close(wfd) # sys.stderr.write('reading..') readstring = read(rfd, 4094) # sys.stderr.write('got it!') while read(rfd, 4096) != '': pass # sys.stderr.write('EOF') waitpid(ret, 0) # sys.stderr.write('reaped') return readstring ekg-1.9~pre+r2855/contrib/scripts/linki.py000066400000000000000000000074711174410337000204370ustar00rootroot00000000000000# -*- coding: ISO-8859-2 -*- # Skrypt ten uruchamia się z poziomu ekg (polecenie python) a zadanie jego to # wyłapywanie adresów URL w otzymanych wiadomościach. Mozna by w tym miejscu poopowiadać o działaniu skryptu # ale myśle ze skypt jest dosć rozmowny pozatym by poczytać helpa (i nie tylko) wystarczy nacisnąć F8 # wszelkie pretensje można kierować na adres: rmrmg(at)wp(dot)pl # # poprawki bezpieczeństwa: wojtekka (2005-07-11) import re import ekg import string import os browser="firefox" link=re.compile(".*http.*") linka=re.compile("http.*") linkfile=os.path.expanduser("~/.gg/rmrmg_ekg_url") def init (): ekg.printf("generic", "linkownik") return 1 def deinit (): ekg.printf("generic", "linkownik poszedł") return 1 def launch(url, tab): url = string.replace(string.replace(url, ",", "%2c"), "'", "%27"); if tab: command = "%s -remote 'openURL(%s, new-tab)'" % (browser, url) else: command = "%s '%s'" % (browser, url) #ekg.printf("generic", "[%s]" % (command)) os.system(command) def handle_msg(uin, name, msgclass, text, time, secure): #ekg.printf("generic", "echo działa") if link.match(text): linki=string.split(text) for x in linki: if linka.match(x): ekg.printf("generic", "znaleziono link: %s" %(x)) ekg.printf("generic", "by otworzyć w: nowym oknie wcisnij F7, nowej zakładce F5, by nie otwierac wciśnijF6.") ekg.printf("generic", "F8 pokazuje liste przechwyconych linków; F5-F7 działa na pierwszym linku z listy") open(linkfile, 'a').write(x + '\n'); #ekg.printf("generic","echo tada") return 1 else: return 1 def handle_keypress(meta, key): if key == 269: ekg.printf("generic", "wciśnieto F5") nurl=czyjest() if nurl == 0: ekg.printf("generic", "nie ma zadnego adresu URL") else: dlug=len(nurl) if dlug == 1: ekg.printf("generic", "otwieram %s w nowej zakładce" %(nurl[0])) launch(nurl[0], True) os.unlink(linkfile) else: ekg.printf("generic", "linków mam %d" %(dlug)) wielejest(nurl) ekg.printf("generic", "otwieram %s w nowej zakładce" %(nurl[0])) launch(nurl[0], True) elif key == 270: ekg.printf("generic", "wcisnięto F6") nurl=czyjest() if nurl == 0: ekg.printf("generic", "nic nie moge skasować - nie ma zadnego adresu URL") else: dlug=len(nurl) if dlug == 1: ekg.printf("generic", "kasuje adres %s" %(nurl[0])) os.unlink(linkfile) else: ekg.printf("generic", "jest wiele linków") wielejest(nurl) ekg.printf("generic", "kasuje pierwszy czyli: %s" %(nurl[0])) elif key == 271: ekg.printf("generic", "wcisnięto F7") nurl=czyjest() if nurl == 0: ekg.printf("generic", "nie ma zadnego adresu URL") else: dlug=len(nurl) if dlug == 1: ekg.printf("generic", "otwieram %s w nowym oknie" %(nurl[0])) launch(nurl[0], False) os.unlink(linkfile) else: ekg.printf("generic", "linków mam %d" %(dlug)) wielejest(nurl) ekg.printf("generic", "otwieram %s w nowym oknie" %(nurl[0])) elif key == 272: ekg.printf("generic", "wcisnięto F8") nurl=czyjest() ekg.printf("generic", "F5 - otwiera w nowej zakładce; F7 w nowym oknie, a F6 kasuje, wszystko tyczy się pierwszej pozycji z listy") if nurl == 0: ekg.printf("generic", "nie ma zadnego adresu URL") else: dlug=len(nurl) ekg.printf("generic", "linków mam %d oto one:" %(dlug)) for po in nurl: ekg.printf("generic", "%s" %(po)) return 1 ########################################################### def czyjest (): if os.path.exists(linkfile): wejsc= open (linkfile) file = wejsc.readlines() dlug=len(file) wejsc.close() #ekg.printf("generic", "liczność %d" %(dlug)) return file else: return 0 def wielejest (buff): file=open(linkfile , 'w') #buff= file.readlines() #file.truncate() #file.writelines file.writelines('\n'.join (buff[1:])) file.close() ekg-1.9~pre+r2855/docs/000077500000000000000000000000001174410337000145475ustar00rootroot00000000000000ekg-1.9~pre+r2855/docs/FAQ000066400000000000000000000135061174410337000151060ustar00rootroot00000000000000Najczęściej zadawane pytania. Q: ... A: Najpierw przeczytaj README, potem TODO. Q: Skąd ściągnąć? A: http://ekg.chmurka.net/ Q: ./configure wyrzuca błędy. Co robić? A: Najprawdopodobniej nie masz narzędzi i pakietów potrzebnych do skompilowania EKG. Upewnij się, że masz zainstalowany kompilator C, narzędzia takie jak make, install, bibliotekę ncurses i odpowiednie pliki nagłówkowe. Q: Jak wysłać wiadomość do kogoś ze spacją w nazwie? A: Wpisać nazwę w cudzysłowach. Niestety dopełnianie jeszcze nie działa jak trzeba. Żeby się nie męczyć, można zmienić w liście kontaktów jego nazwę: ,,list --display bezspacji''. Q: Jak zarejestrować nowego użytkownika? A: Użyć polecenia ,,token'' i ,,register ''. Q: Kiedy zrobicie w ekg wsparcie dla UTF-8? A: Jest w planach. Póki co jest kilka obejść: - screen jednorazowo: Ctrl-A, dwukropek, encoding iso8859-2 utf-8, enter, Ctrl-L - screen na stałe: dopisanie 'bind i encoding iso8859-2 utf-8' do ~/.screenrc i żeby aktywować: Ctrl-A i - luit (zadziała w bashu): LANG=pl_PL luit ekg Q: Jak wysłać smsy? A: Patrz pierwsza odpowiedź. Jest opisane w dokumentacji. Q: Jak pobrać listę użytkowników z serwera lub ją tam umieścić? A: Odpowiednio ,,list --get'' i ,,list --put''. Q: Jak zmienić informacje w katalogu publicznym? A: Użyć polecenia ,,change''. Q: Jak wysłać lub odebrać plik albo prowadzić rozmowy głosowe? A: Przeczytać szybki kurs z pliku ,,dcc.txt''. Q: Można otworzyć osobne okienko do rozmowy? A: Jasne. Tworzymy nowe okno (,,window new''), przełączamy się na nie (,,window next'', ,,window switch NR'', lub Alt+1-9) i ,,query nick''. Istnieje też zmienna ,,make_window'', dzięki której każda nowa rozmowa tworzona jest w osobnym okienku (zobacz ,,vars.txt''). Q: Nie chce się łączyć, a windziany klient działa! Co jest? A: Najwyraźniej padł jeden z serwerów. Wpisz ,,set server 217.17.41.x'', gdzie x to wartość od 82 do 89 i spróbuj połączyć się jeszcze raz. Q: Jak usunąć zmienną? A: ,,set -zmienna''. Q: ekg źle rozpoznaje płeć! A: Wpisz imię do listy kontaktów. Więcej szczegółów w README. Q: Jak zrobić, żeby ekg pokazywało mój pseudonim przy wysyłaniu wiadomości? A: Ustawić zmienną ,,nick''. Q: Dlaczego w logach zamiast czasu jest jakaś dziwna liczba? A: Czas jest zapisywany jako ilość sekund od 1 stycznia 1970 UTC. Dzięki temu różne programy i skrypty nie będą miały problemów z analizowaniem historii rozmów. Do czytania historii dołączone są skrypty o nazwach ekl w katalogu contrib/. Możesz również zmienić zmienną ,,log_timestamp'' i dostosować format czasu do swoich potrzeb (,,man 3 strftime''). Q: Po zmianie wielkości terminala przestają mi działać strzałki! A: Masz starą wersję biblioteki ncurses. Zainstaluj nowszą wersję lub poproś o to administratora systemu. Q: Jak wyświetlać wiadomości, które wysyłam? A: ,,/set display_sent 1''. Q: Nie mam kolorów w ekg, co robić? A: Najprawdopodobniej masz ustawiony nieprawidłowy typ terminala. Spróbuj wpisać ,,export TERM=ansi'' (lub ,,setenv TERM ansi'' dla powłoki *csh) przed uruchomieniem ekg. Jeśli to nie pomoże, zamiast ,,ansi'' spróbuj podać ,,screen'', ,,linux'', ,,xterm-color'' lub ,,color_xterm''. Q: Jak się zarejestrować, usunąć konto, zmienić hasło lub przypomnieć hasło? A: Należy wydać polecenie ,,/token'', które pobierze z serwera token niezbędny do przeprowadzenia tych operacji. Jeśli podczas kompilacji w systemie była zainstalowana biblioteka libungif, zostanie on wyświetlony na ekranie. W innym wypadku należy odczytać podany plik. Wartość tokenu należy podać jako ostatni parametr komend ,,/register'', ,,/unregister'', ,,/passwd'' lub ,,/remind''. Q: Co oznacza komunikat "Wiadomość do najprawdopodobniej nie została dostarczona"? A: Komunikat taki ekg wyświetla, gdy dana osoba jest niedostępna, a serwer twierdzi, że doręczył wiadomość. Najczęściej sytuacja taka ma miejsce, gdy wiadomość została odrzucona przez filtry serwera (np. zawiera adres strony WWW) lub osoba ma pełną skrzynkę wiadomości. Q: Lista kontaktów jest zbyt wąska. Jak można to zmienić? A: Komenda ,,/set contacts_size 12'' powinna pomóc. W razie potrzeby można dowolnie zmniejszać lub zwiększać wartość. Q: Jak mogę zwiększyć ilość linii rozmowy dostępnych do przeglądania? A: Przyda się zmiana ustawienia zmiennej ,,backlog_size'', chociażby na 100. Q: Chcę aby wyświetlany format czasu był bardziej szczegółowy, jak to zrobić? A: ,,/set timestamp %H:%M:%S'' - wyświetlane będą również sekundy. Q: Jak ukryć się przed sprawdzaniem czy jestem niewidoczny? A: Ustawić zmienną ,,ignore_empty_msg'' na ,,1''. Q: Jak mogę stworzyć archiwum rozmów? A: Najkrótszy sposób to wydanie komend: set log 2 set log_path ~/.gg/archiwum Polecenie ,,/set log_ignored 1'' umożliwia logowanie także ignorowanych wiadomości. Q: Przy rozmowie z wieloma osobami i zamknięciu jednego okna powstaje ,,luka'' w numeracji. Jak można temu zapobiec? A: W tym wypadku należy zmiennej ,,sort_windows'' przypisać wartość ,,1''. Q: Jak włączyć opcję ,,tylko dla znajomych''? A: Wydaj komendę ,,/private on''. Q: Na mojej liście kontaktów nie widzę osób niedostępnych. Co mam zrobić? A: ,,/set contacts_options order=5016234''. Q: Mam najnowsze ekg (current) z /dnd i /ffc ale gdy ktoś zmienia stan na "poGGadaj ze mną" to widzę że zmienił na dostępny, a gdy na "nie przeszkadzać" - zajęty. A: Wpisz ,,/set protocol 0x2E''. Jest to konieczne do czasu wydania nowego stabilnego libgadu. Q: Mam najnowsze ekg (current), ale nie widzę na liście kontaktów osób z dnd i ffc. Co zrobić? A: ,,/set contacts_options order=5016234''. Q: Czy jest możliwość żeby określone polecenia były wykonywane po starcie programu? A: Tak, służy do tego alias ,,autorun''. Q: Zepsułem, alias ,,autorun'' uniemożliwia korzystanie z programu! A: Użyj opcji -A i usuń ten alias. $Id$ ekg-1.9~pre+r2855/docs/IDEAS-2.0000066400000000000000000000175141174410337000156240ustar00rootroot00000000000000// krótki opis mojej wizji ekg-2.0 // 20030416 wojtekka jeśli dobrniesz do końca tekstu, byłbym bardzo wdzięczny za komentarze i sugestie. nie chcę robić niczego wbrew reszcie świata. wszystko wyrzucić do pluginów. ekg samo w sobie nie powinno umieć się z niczym łączyć, ani nic wyświetlać. ma zawierać funkcje obsługi pluginów, obsługi komend, obsługi zmiennych i kilku kawałków kodu, które mogą być dzielone między pluginami (np. formatowanie tekstu, konferencje, przypisane klawisze). nie wszystkie pluginy muszą być ładowane dynamicznie. kilka na pewno będzie domyślnie linkowanych statycznie -- chodzi o możliwość łatwego pozbycia się zależności głównej binarki od wielu bibliotek i zachowanie jednolitego API. do głowy przychodzi mi kilka klas pluginów: 1) pluginy interfejsu użytkownika -- czyli to, co do tej pory robią ui-readline i ui-ncurses. dojdzie do tego plugin obsługujący rurki, sockety lokalne i inne sposoby sterowania klientem. 2) pluginy protokołów -- priorytetem ekg będzie zawsze ,,wzorcowa'' obsługa Gadu-Gadu, ale nie można stać w miejscu. wielu ludziom brakuje porządnego klienta Jabbera pod konsolę. co więcej, istniejący kod konferencji, po lekkim rozszerzeniu może stanowić podstawy pod obsługę irca. niestety ciężko będzie od razu zaplanować API pozwalające na napisanie obsługi dowolnego protokołu na ziemi, więc każdy nowy plugin tak czy inaczej będzie wymagał drobnych zmian w ekg. ale będą mogły się rozwijać niezależnie. 3) pluginy szyfrujące -- póki co, jest tylko SIM, ale nic nie stoi na przeszkodzie, żeby ekg obsługiwało prostsze sposoby szyfrowania, np. symetryczne z hasłem. 4) pluginy skryptów -- mamy pythona. znajomy poradził, żeby umożliwić pisanie skryptów również w innych językach. nie powinno być trudne, zwłaszcza, że obsługa skryptów ogranicza się do ładowania, usuwania, wykonywania poleceń i wywoływania funkcji. API takiego pluginu można ograniczyć do kilku funkcji. poza tym, za pomocą skryptów powinno być możliwe tworzenie każdej klasy pluginów. 5) pluginy dźwięku -- jest tylko oss, a to nie wszystkim pasuje. dodawanie dziesiątek #ifdefów do obsługi różnych systemów jest bez sensu. poza tym, jeśli zrobić plugin, który zamiast z mikrofonu, czyta z socketa, mamy proste radio, które chociaż jakością nie grzeszy, zajmuje bardzo małe pasmo. do tego możnaby też doliczyć pluginy kodujące dźwięk, żeby inne pluginy mogły poprosić od razu o strumień GSM czy MP3. 6) pluginy historii -- widać, że nie wszystkim odpowiada sposób logowania w ekg. tutaj wystarczy w zasadzie jedna funkcja dopisująca do historii określone zdarzenie, ale możliwość odczytu też by się przydała, żeby móc w ekg przeglądać historię (ach, pobożne życzenia!). póki co, są już pomysły na 4 pluginy: legacy-ekg, all-new-kadu, sql i xml. głupio byłoby linkować ekg z sqlem i expatem. 6) pluginy ogólnego przeznaczenia -- tutaj pasowałby chociażby ioctld, który dodaje dwie nowe komendy, więc ciężko podpiąć go pod interfejs użytkownika. pasowałby też każdy skrypt, który nie pełni roli jakiegoś plugina. każdy plugin dodawałby swoje komendy, zmienne i zdarzenia. mógłby wywoływać zdarzenia dla innych pluginów. ekg podczas ładowania wywoła funkcję typu register_plugin(), która będzie miała za zadanie zarejestrować wszystkie udostępniane komendy i zmienne. w przypadku konfliktu zmiennych i komend, można je poprzedzić prefiksem określającym plugin. jeśli na przykład mamy załadowaną obsługę GG i Jabbera, zmienna ,,gg:password'' określałaby hasło GG, ,,jabber:password'' określałaby hasło Jabbera. jeśli użytkownik nie poda o jaki plugin chodzi, a np. aktualne okno to sesja GG, brany pod uwagę byłby plugin ,,gg''. jeśli okno Jabbera, plugin ,,jabber''. podobnie z komendami. jeśli ktoś w oknie Jabbera chciałby zarejestrować konto GG, wystarczyłoby ,,/gg:register''. pluginy muszą posiadać również informacje o kolizjach z innymi, żeby przy ładowaniu ,,ncurses'' usunąć ,,readline'' i na odwrót, bo oba korzystają z terminala. obsługa okien powinna trafić do ekg. ui ma wyświetlać to, co każe mu pokazać ekg i informować o wciśniętych klawiszach funkcyjnych (nie chodzi tylko o Fx tylko o Alt-x, Ctrl-x itp.) dzięki temu przy zmianie ui, okna zostaną zachowanie (to ma być efekt uboczny, a nie cel sam w sobie.) pozostaje kwestia interakcji pluginów z ekg i między sobą, oznaczania zdarzeń, kompatybilności API i takichtam bzdur. najprawdopodobniej będzie coś w rodzaju gtk-owych sygnałów. plugin sobie zarejestruje obsługę danych sygnałów, przez co odpadną dziesiątki strcmp(), jak to ma miejsce teraz, przy jednej funkcji callbackowej na cały plugin. niestety będzie to wymagało porządnego zastanowienia się nad tym, jak zrobić to efektywnie. setki strcmp() przy każdym pakiecie przychodzącym z sieci i przy wywołaniu sekundowego timera to przesada. niestety nie studiuję informatyki, więc pewnie na początku będzie to sporym problemem. w każdym razie optymalizację przekierowywania sygnałów można zostawić na później, kiedy będzie już co optymalizować. jeśli chodzi o API, ekg od chwili ustandaryzowania pierwszej wersji API pluginów będzie oznaczało plugin jakimśtam identyfikatorem wersji. będzie trzymać wszystkie stare wersje struktur i funkcji, żeby stare pluginy mogły ich użyć. trzeba będzie też wprowadzić zmienne typu lista, żeby móc np. podać listę rurek kontrolnych (np. ,,pipe:/tmp/rurka'', ,,tcp:12345'' i ,,socket:/var/run/ekg''), z których ekg ma przyjmować polecenia, interfejsów audio na wypadek zajętości (np. ,,/dev/dsp'', ,,hw:0,2'' czy ,,tcp:8001'') no i wreszcie naszych ukochanych serwerów (przykładu nie ma. wybaczycie?) co do wielosesyjności i wieloprotokołowości, to podobnie jak w BitchX czy irssi, jedno okno mogłoby mieć przypisanych kilka sesji, które zmienianoby klawiszem Ctrl-X na przykład. zmieniałby się pasek stanu między: (17:25) (gg:535333) (win/1) (17:25) (jabber:wojtekka@jabber.org) (win/1) (17:25) (irc:elluin@poznan.irc.pl) (win/1) oczywiście powinna być możliwość przypisywania danym sesjom jakichś aliasów, żeby nie mieć całego paska stanu zajętego przez id sesji. pozostaje kwestia userlisty. robić osobną na każdy protokół i sesję? osobną na każdy protokół, ale sesje dzielą? bo albo możemy chcieć wpisać sobie jednego użytkownika jako gg:123456, irc:ktośtam, jid:ktośtam@gdzieśtam.pl i raz podać imię, nazwisko, numer telefonu itd, albo trzymać wszystko oddzielnie dla każdego protokołu, bo np. podczas rozmów na GG nie chcemy zaśmiecać sobie listy znajomymi, których numery były kiedyśtam wpisane, ale i tak rozmawiamy tylko na ircu. wypadałoby też w końcu oddzielić libgadu od ekg, skoro ekg ma obsługiwać inne protokoły. nie dość, że ulży to autorom innych klientów GG, wymusi większy porządek w API, wersjach i binarnej kompatybilności. z okazji pluginów, dobrze byłoby też się przyjrzeć takim wynalazkom jak automake i libtool. rozmiar pakietu wzrośnie, ale nie będzie problemów z obsługą platform innych niż te, na których pracują autorzy (pomyśleć, że jeszcze 2 lata uważałem autoconfa za zło wcielone. pod postacią software'u.) // 2003-04-17 12:53 może jednak zrobić bloga? (; w każdym razie dla testów wydzieliłem libgadu ze źródeł ekg, przerobiłem do automake i libtoola. faktycznie, pisania mniej, ale rozmiar wszystkich narzędzi, które autogen.sh pakuje do katalogu mnie przerasta. tarball z Makefile.am, configure.in i autogen.sh zajmuje 80kB, a po wygenerowaniu wszystkiego 320kB. trochę to chore. jeśli ekg miałoby mieć dla każdego plugina tyle śmieci, to ja chyba podziękuję. innym wyjściem byłoby rozprowadzanie tarballi bez tego wszystkiego i wymaganie od ludzi posiadania pełnego środowiska: gcc, binutils, make, autoconf, automake, libtool. ludzie, którzy mają wszystko nie musieliby ściągać niepotrzebnie kilka razy większego tarballa. co najwyżej możnaby tworzyć osobny ekg-current-foobar.tar.gz, który miałby wszystko, ale go nie archiwizować. w sumie to możliwe, od kiedy na dev.null.pl stoi PLD. ekg-1.9~pre+r2855/docs/README000066400000000000000000000423271174410337000154370ustar00rootroot00000000000000 Eksperymentalny Klient Gadu-Gadu (C) Copyright 2001-2007 Autorzy (pełna lista poniżej) LICENCJA Program jest udostępniony na zasadach licencji GPL v2, której treść załączono w pliku src/COPYING. Niektóre pliki mogą być objęte inną licencją zgodną z GPL v2. Fakt ten jest odnotowany na początku pliku. Wyjątkiem od licencji GPL v2 jest możliwość kompilacji, konsolidacji i używania programu z biblioteką OpenSSL autorstwa Projektu OpenSSL (The OpenSSL Project) dostępną pod adresem http://www.openssl.org/ Program ekg i biblioteka libgadu zostały napisane na podstawie informacji uzyskanych przez badanie pakietów wysyłanych między klientem a serwerem oraz od osób trzecich. Autorzy nie disasemblowali ani nie dekompilowali oryginalnego klienta. Projekt powstał przy użyciu darmowych i wolnodostępnych narzędzi. Gadu-Gadu jest zastrzeżonym znakiem towarowym Gadu-Gadu S.A. WYMAGANIA Do komunikacji z serwerami Gadu-Gadu program wymaga biblioteki libgadu, która jest udostępniona oddzielnie. Więcej informacji o tym jak ją pobrać i zainstalować, znajdziesz w pliku libgadu.txt Program domyślnie korzysta z biblioteki ncurses, więc powinny być zainstalowane odpowiednie pakiety zawierające bibliotekę oraz pliki nagłówkowe. Jeśli chcesz użyć starego interfejsu, do polecenia configure dodaj ,,--disable-ui-ncurses''. Interfejs ten wymaga zainstalowania biblioteki readline wraz z plikami nagłówkowymi. readline zwykle polega też na innych bibliotekach do obsługi terminala, jak np. libtermcap czy ncurses. Instalacja obu interfejsów naraz nie jest wskazana. Oczywiście niezbędny jest też zestaw narzędzi do kompilacji programów napisanych w języku C -- kompilator, preprocesor, linker, pliki nagłówkowe, biblioteki systemowe itd. Jeśli skrypt ./configure zgłosi jakieś błędy, skontaktuj się ze swoim administratorem. ekg powinien działać na większości systemów uniksowych, jak Linux, *BSD, SunOS, IRIX itp. lecz czasami przy dodawaniu nowych funkcji nie sposób sprawdzić ich zachowania na wszystkich popularnych systemach. W takim wypadku przydatne są informacje o błędach z dokładnym wskazaniem systemu i architektury. INSTALACJA Rozpakować poleceniem ,,tar zxvf ekg-XXX.tar.gz'' (gdzie XXX to wersja programu lub data wykonania snapshotu), wejść do utworzonego katalogu. Jeśli mamy uprawnienia administratora na danej maszynie, wywołujemy ,,./configure'', potem ,,make'' i z prawami roota ,,make install''. Jeśli chcemy zainstalować program w katalogu domowym, do polecenia configure dodajemy parametry ,,--prefix=$HOME/ekg --mandir=$HOME/ekg/share/man''. Po zainstalowaniu w ten sposób, program gotowy do uruchomienia będzie znajdował się w katalogu ekg/bin w katalogu domowym. Jeśli chcemy mieć możliwość używania poleceń ,,beeps_spk'' i ,,blink_leds'', służących m.in do manipulowania diodami LED na klawiaturze, należy przy uruchomieniu użyć parametru ,,--enable-ioctld''. Proste? Proste. Po pierwszym uruchomieniu ekg powie, jak go skonfigurować. UŻYCIE Jest na tyle intuicyjne, że nie powinno sprawić problemów (wszyscy betatesterzy poradzili sobie bez jakiejkolwiek dokumentacji). Interfejs jest wzorowany na irssi. Dopełnianie tabem jest dostępne w większości komend. Komendy można wywoływać skrótami, o ile są one jednoznaczne. Wysyłanie wiadomości komendą ,,msg'', otwarcie okna rozmowy komendą ,,query''. Informacje o rozmówcach ,,find'' w oknie rozmowy. Szukanie tą samą komendą, ale z różnymi parametrami. ,,help'' Twoim przyjacielem. Jeśli dana komenda ma różne opcje, pomaga ,,help ''. By wysłać kilkulinijkową wiadomość w interfejsie ncurses, wciśnij Ctrl-Enter. W readline zamiast treści wpisz ,,\'' (backslash) i zakończ linią z samą kropką (szczegóły poniżej, w rozdziale ,,KLAWIATURA''). Program można skonfigurować pod wieloma względami, a wszystkie możliwe ustawienia, które zmienia się poleceniem ,,set'', są opisane w pliku vars.txt. Pomoc dotyczącą poszczególnych ustawień można uzyskać także poprzez polecenie ,,help set ''. Jeśli dana komenda przyjmuje ,,--parametr'', można użyć również skrótu ,,-p'', gdy nie powoduje to niejednoznaczności. Uwaga! Brana pod uwagę jest zwykle pierwsza litera, więc jeśli chcesz skrócić ,,list --gone'' do ,,list -g'', ekg potraktuje to jako ,,list --get''. Komendy można wysyłać także przez potok. By go uaktywnić, należy uruchomić ekg z parametrem ,,-c'' i ścieżką potoku. Ze względu na specyfikę potoków, wyniki poleceń wysyłane będą na terminal, na którym jest uruchomione ekg (tak jak normalnie). Pisać do potoku można tak jak do normalnego pliku (choćby poleceniem echo). Jeśli w linii poleceń shella podasz po nazwie programu i parametrach zaczynających się od myślnika coś jeszcze, to zostanie to zinterpretowane jako komenda wsadowa. ekg połączy się z serwerem, wykona tylko tę komendę i od razu wyjdzie. Jeśli na serwerze czekają na Ciebie jakieś wiadomości, to serwer je przyśle zaraz po połączeniu i w trybie wsadowym ekg wypisze je na terminal. Jeśli zamierzasz przekierować wyjście do /dev/null i nie masz włączonego logowania, wiadomości zginą bezpowrotnie. KLAWIATURA Jeśli nie masz doświadczenia w obsługiwaniu programów z emacsową filozofią obsługi klawiatury, oto lista obsługiwanych klawiszy: Up, Down przeglądanie historii poleceń Left, Right poruszanie się po aktualnej linii Ctrl-A, Home idź na początek linii Ctrl-B pogrubiona czcionka [3] Ctrl-D, Delete usuń znak pod kursorem Ctrl-H, Backspace usuń znak przed kursorem Ctrl-I, Tab dopełnianie Ctrl-K usuwa tekst od kursora do końca linii Ctrl-L czyszczenie/odświeżanie ekranu Ctrl-M, Enter zatwierdzenie linii Ctrl-Q odblokowanie terminala Ctrl-R kolor tekstu [3] Ctrl-S zablokowanie terminala Ctrl-T pochyła czcionka [3] Ctrl-V pozwala wpisać dowolny znak [2] Ctrl-U usunięcie aktualnej linii Ctrl-W, Alt-Backspace usunięcie słowa przed kursorem Ctrl-Y wklejenie ostatnio usuniętego bloku Ctrl-Z przeniesienie programu w tło Ctrl-_ podkreślona czcionka [3] Alt-B słowo do tyłu Alt-D usunięcie słowa za kursorem Alt-F słowo do przodu Alt-cyfra przełączenie do podanego okna F1 pomoc F2 krótka lista dostępnych i zajętych F12 lub Alt-` przełączenie do okna debugowania Lista ta obejmuje klawisze obsługiwane przed interfejs readline i ncurses, i nie zawiera kombinacji specyficznych dla tego pierwszego. Interfejs readline obsługuje również inne kombinacje klawiszy. Dokładna lista znajduje się w stronie manuala ,,readline'' w rozdziale ,,DEFAULT KEY BINDINGS''. Dodatkowo: Ctrl-D zamyka rozmowę i anuluje wprowadzanie wiadomości wielolinijkowej Interfejs ncurses obsługuje kilka dodatkowych kombinacji: Page Up, Page Down przewijanie ekranu Ctrl-F, Ctrl-G j.w. Alt-A przejdź do pierwszego aktywnego okna Alt-S przejdź do najstarszego aktywnego okna (okna, które najdłużej jest aktywne) Alt-N utwórz nowe okno Alt-K zamknij aktualne okno Alt-G ignoruj aktualnego rozmówcę Alt-Q do Alt-P przełącza do okna 11 do 20 Alt-Z przewijanie listy kontaktów w górę Alt-X przewijanie listy kontaktów w dół Ctrl-Fn przełącza do podanego okna (konsola FreeBSD) Ctrl-Enter przejście do trybu wielolinijkowego Ctrl-P poprzednie okno Ctrl-N kolejne okno F3 włącza lub wyłącza listę kontaktów [1] F4 kolejna grupa w liście kontaktów F11 wybór informacji w pasku statusu Po wejściu do trybu wielolinijkowego poruszamy się za pomocą kursorów i zatwierdzamy ponownym wciśnięciem Ctrl-Enter. By anulować, wciskamy Esc i czekamy chwilę. Jeśli kombinacja ta nie jest obsługiwana przez terminal, można używać Alt-Enter lub wcisnąć Esc i zaraz po nim Enter. Dodatkowo, określonym kombinacjom klawiszy można przypisać różne komendy za pomocą polecenia ,,bind''. Ze względu na niestandardowe zachowanie niektórych typów terminali, mogą wystąpić problemy z kombinacją Alt-Shift-O lub Alt-O przy włączonym Caps Locku. [1] Klawisz F3 zmienia wartość zmiennej ,,contacts''. Jeśli wartość tej zmiennej była równa 0, wciśnięcie klawisza zmienia jej wartość na 2. Jeśli była równa 1, kolejne wciśnięcia F3 będą zmieniały wartość z 1 na 0 i z 0 na 1. [2] Po wciśnięciu Ctrl-V należy wcisnąć klawisz, który chcemy wkleić. Dzięki temu możliwe jest wpisanie znaków typu Escape, Ctrl-L czy Ctrl-U. [3] W miejscu wciśnięcia klawisza pojawi się znak oznaczający kod klawisza w negatywie. By zmienić kolor tekstu, należy po Ctrl-R wpisać numer koloru od 0 do 15. PLIK KONFIGURACYJNY Kolejność ładowania plików konfiguracyjnych jest następująca: 1) /etc/ekg.conf (lub z innego katalogu wskazanego przez opcję --sysconfdir przekazaną skryptowi ./configure), 2) ~/.gg/config lub ~/.gg//config, 3) /etc/ekg-override.conf Dzięki temu administrator może wymusić pewne opcje na klientach użytkowników, jak na przykład ,,server'' czy ,,proxy''. Globalne pliki konfiguracyjne można ignorować przez uruchomienie klienta z opcją ,,-N''. GDZIE SZUKAĆ POMOCY Dobra rada numer jeden: zanim zaczniesz narzekać, że czegoś nie ma, przeczytaj plik TODO. Dobra rada numer dwa: plik ULOTKA mówi, co znajduje się w którym pliku dokumentacji. Dobra rada numer trzy: zanim zaczniesz narzekać, że czegoś nie ma, poszukaj w pliku ChangeLog. Dobra rada numer cztery: jeśli jesteś nowym użytkownikiem, nie pytaj się, czy coś da się zrobić, albo że przydałoby się. Program jest rozwijany od kilku lat, wielu ludzi korzysta z niego na co dzień, więc większość ,,bajerów'', o których możesz pomyśleć, na pewno jest już w programie. WYSYŁANIE SMSÓW ekg korzysta z zewnętrznego programu do wysyłania smsów. Nie ma najmniejszego sensu dublowania tej funkcji, skoro i tak większość ma już zainstalowane odpowiednie skrypty/programy/cokolwiek. Wystarczy podać ścieżkę do takiego programu w zmiennej ,,sms_send_app''. Powinien przyjmować numer telefonu za pierwszy parametr i wiadomość za drugi. Ten ze strony http://ceti.pl/~miki/ spełnia podane wymagania. SYNTEZA MOWY ekg potrafi korzystać z zewnętrznej aplikacji do syntezy mowy, by odczytywać wszystko, co trafia na ekran. Wystarczy ustawić zmienną ,,speech_app'' na nazwę programu czytającego tekst z stdin. Jej ustawienie spowoduje również zmianę wyglądu programu, by wyświetlane komunikaty stały się łatwiejsze do wymówienia. Przykładowe ustawienia, gdy korzystamy z programu ,,powiedz'', to: set speech_app powiedz set make_window 0 set display_sent 0 set display_ack 3 Program ,,powiedz'' można pobrać z http://cvs.pld.org.pl/SOURCES/powiedz_0.2.tgz ZNANE PROBLEMY Jeśli nie możesz wpisywać polskich liter w interfejsie readline, dopisz do pliku /etc/inputrc lub ~/.inputrc następujące linie: set meta-flag on set convert-meta off set output-meta on ROZPOZNAWANIE PŁCI Krótka wersja: Jeśli ekg źle rozpoznaje płeć, wpisz imię do listy kontaktów. W większości przypadków pomoże. No tak, nie masz pojęcia, jak to zrobić? ,,list pseudonim -f imię''. Pomogło? Świetnie. Nie pomogło? Czytaj dalej. Długa wersja: Jedną z najbardziej kontrowersyjnych cech programu jest automatyczne rozpoznawanie płci na podstawie ostatniej litery imienia lub gdy jest ono nieznane, pseudonimu. Gdy ostatnią literą jest ,,a'', ekg uznaje, że dana osoba jest kobietą. Na przykład, jeśli Twój znajomy ma pseudonim ,,Kuba'', wpisz do listy kontaktów imię ,,Jakub''. Problemy mogą wystąpić z rzadko spotykanymi imionami typu Barnaba czy Mercedes. W takim wypadku należy do imienia dopisać (chociażby po ukośniku lub w nawiasie) literę ,,a'' dla kobiet lub inną niż ,,a'' dla mężczyzn. ZGŁASZANIE BŁĘDÓW Jeśli zauważysz jakiś błąd, sprawdź najnowszą wersję. Większość błędów jest poprawiana w ciągu jednego lub dwóch dni od chwili pojawienia się. Przy zgłaszaniu błędu zaznacz, w której wersji występuje. Nie pisz o sprawach, które są już wymienione w pliku TODO, bo doskonale wiemy, że coś trzeba poprawić. Zaznacz, co to za system, jaka dystrybucja, jaka wersja. Jeśli błąd jest powtarzalny i związany z siecią, przejdź do okna debug i przyślij to, co zostaje tam wyświetlone przed samym wystąpieniem błędu (zwykle ~20 linijek wystarczy). Możesz też skorzystać z ukrytego polecenia ,,_debug_dump'', które zapisze ostatnie linie z debug do pliku lub też przed uruchomieniem ekg wpisać nazwę pliku, do którego przekierowany będzie debug, do zmiennej systemowej ,,EKG_DEBUG''. Jeśli program powoduje naruszenie ochrony pamięci i powstaje plik ,,core'', postępuj zgodnie z instrukcjami pokazanymi na ekranie -- uruchom ,,gdb ekg core'', przyślij to, co się pojawi. Potem wydaj polecenie ,,bt'' i jego wynik również załącz do listu. Jeśli błąd może mieć coś wspólnego z siecią, wyślij utworzony plik ,,debug''. Jeśli program się zawiesi, nie reaguje na nic i zajmuje 100% czasu procesora, w innym oknie terminala wydaj polecenie ,,strace -p '', gdzie to numer procesu ekg (uzyskasz go poleceniem ,,ps x'') i wyślij ostatnie 20 linii. Informację o błędzie należy przesyłać na listę ekg-users (nie trzeba się na nią zapisywać, szczegóły niżej), ponieważ w ten sposób dostaną ją (prawie) wszyscy autorzy kodu. Możliwe też, że któryś z użytkowników natknął się na to samo i wie, jak sobie z tym poradzić. ŹRÓDŁA Snapshoty kodu są dostępne pod adresem http://ekg.chmurka.net/ Jeśli nie wystąpi żadne trzęsienie ziemi, brak prądu ani barykady na drogach, powinny być robione co 24 godziny, wieczorem. Poza snapshotami, co jakiś czas będą umieszczane na serwerze kolejne wersje klienta. Ze względu na organizację prac nad programem, w praktyce nie będą się one różnić znacznie od snapshotów. Przed wydaniem każdej wersji wstrzymane będzie dodawanie nowych opcji, by skupić się na usuwaniu błędów. Poza tym, ułatwi to pracę niektórym osobom zajmującym się tworzeniem paczek dla dystrybucji -- zamiast uaktualniania ich do nowych snapshotów, będą miały możliwość pakowania ,,stabilnych'' wersji. Część kodu jest ładnie udokumentowana, część nie. Komentarze czasami są bardzo głupie, ale jeśli się do trzeciej rano siedzi nad dziwnym segfaultem, ciężko się pohamować. Jeśli napiszesz jakiegokolwiek klienta, frontend czy coś takiego, daj znać -- odnośnik do projektu zostanie umieszczony na stronie ekg. LISTA DYSKUSYJNA Istnieje lista dyskusyjna dla użytkowników ekg o adresie ekg-users@lists.ziew.org. Aby się zapisać, należy wejść na stronę o adresie: http://lists.ziew.org/mailman/listinfo/ekg-users oraz postępować według instrukcji tam zawartych. AUTORZY Wymienione osoby miały mniejszy lub większy wpływ na rozwój biblioteki i klienta. Niektórzy pisali kod, pomagali analizować protokół, testowali na różnych systemach, inni podsyłali patche i bugreporty. Jeśli ktoś został pominięty, niech da znać. W każdym razie za to, jak wygląda ekg, odpowiedzialni są (w porządku alfabetycznym): Marek Antoniak Wojciech Bojdoł Kamil Brzeziński Tomasz Chiliński Marcin Chojnowski Piotr Domagalski Michał Dorociński Tomasz Dudzisz Piotr Figiel Rafał Florek Artur Gawryszczak Stanisław Gurgacz Darek Jackowski Rafał Janiczek Dawid Jarosz Tomasz Jarzynka Kuba Jermak Jarosław Kamper Asia Kaniewska Wojtek Kaniewski Maciej Korzeń Paweł Kot Marek Kozina Adam Kruszewski Piotr Kupisiewicz Adam Ludwikowski Jakub Martyński Paweł Maziarz Marcin Mikuła Arkadiusz Miśkiewicz Jacek Osiecki Robert Osowiecki Adam Osuchowski Marcin Owsiany Maurycy Pawłowski Artur Pietruk Jacek Pospychała Paweł Pruszkowski Jacek Rembisz Rafal Roszak Krzysztof Składzień Rafał Skoczylas Adrian Smarzewski Walerian Sokołowski Piotr Stolc Tomasz Torcz Leszek Urbański Robert J. Woźny Krzysztof Wójtowicz Adam Wysocki Piotr Wysocki $Id$ ekg-1.9~pre+r2855/docs/TODO000066400000000000000000000061271174410337000152450ustar00rootroot00000000000000Nie zawracaj ludziom głowy i nie pisz, że chciałbyś coś zaproponować, jeśli zostało wymienione na poniższych listach. Listy lub wiadomości, żeby coś z nich dostać będą albo ignorowane, albo odpowiedź może być nieprzyjemna. Zwykle im dana sprawa jest wyżej na liście, tym ważniejsze jest jej rozwiązanie. * klient: - dostosowanie do UTF-8 (wielu) - poprawić wysyłanie długich szyfrowanych wiadomości (coś się zmieniło i wiadomość jest dzielona na dwie, z czego druga nie jest już deszyfrowana, poza tym obcinanie za długiej wiadomości przy wyświetlaniu kuleje - jest obcinana tak jakby nie była szyfrowana) (gophi) - możliwość bindowania myszy (gophi) - informacja o opisie w /find (scooty/w) - zawijanie linijek w wielolinijkowym (?) - wykrywanie niewidocznych jako opcja (wielu) - czas powrotu w stanach opisowych (?) - uporządkowane i dobrze działające okna pływające (sz?) - możliwość automagicznego wyrównywania kolejnych linii wiadomości w tematach ircopodobnych do długości nazwy rozmówcy i timestampu (sz) - lista kontaktów w pierwszym oknie, rozmowy w kolejnych (jojo) - osobna historia dla każdego okna (koniu) - zapisywanie backlog'a z okna do pliku (G.Sulek, lukzg) - %{date} (GhosT) - dalsza rozbudowa on (?) - zaprzeczenia i inne operatory (krzyk) - możliwość definiowania kolorów pływających okien: tło, ramka (w) - ,,wjeżdżanie'' i automatyczne chowanie listy kontaktów, coś na wzór pasku zadań w windowsach (w) - możliwość blokowania terminala po dłuższym czasie nieaktywności (Gambler) - okienka oparte o kolejne wywołania xterma (fidor) - logowanie własnych statusów (ramzes) - /reload i wypisanie informacji o konieczności ponownego połączenia (zmienne dotyczące dcc) (zigi) - przekierowanie wyniku komend do pliku, rozmowy itp. - /set ignorujący wszystkie konferencje (rodion) - przeglądarka historii - zdarzenia ze spacjami w nazwie (ramzes) - potwierdzenia dostarczenia wiadomosci w konferencji w jej oknie (kip, jceel) - wielolinijkowe /on i opisy - nie działa zapis w konfigu - "19:37:22 -- autosaving userlist and config after 1989 seconds." (jakiś overflow?) - gdy lista aktywnych okienek nie mieści się na pasku stanu, w ostatnim znaku pasku stanu jest wypisywana jakaś cyfra (kawałek numerka któregoś okienka, które się nie zmieściło?) - /set: rozpoznawanie szyfrowania u rozmówcy po treści wiadomosci (jceel) - /set: irssi_log_mode (cześ) - zapisywanie opisu po zabiciu sygnalem (dude) - niekończąca się rekurencja po zapętleniu aliasów (/alias -A abc abc i potem /abc) (k4myk) - w theme: sent_line 2:%2 3:%3 4:%4 5:%5 6:%6 7:%7 8:%8 9:%9 %b|%n %|%1%n\n (met) - unignore (gdy było ignore status) nie przywraca stanu danej osoby - możliwość używania $ w okienkach z konferencjami (jceel) - ignorowanie stanu powinno ukrywać adres ip, wersję itd. - ostrzeganie, gdy userlista/blocklista jest pełna (jest sens?) - poprawienie warningow signed/unsigned na gcc-4 - nowe nazwy obrazków i dcc (po zmianie przez dcc_backups) powinny być prawidłowo przekazywane do obsługi zdarzenia dccfinish (gophi) $Id$ ekg-1.9~pre+r2855/docs/ULOTKA000066400000000000000000000042371174410337000154770ustar00rootroot00000000000000 "Czytanie dokumentacji może powodować raka i choroby serca" minister do spraw informatyzacji i Windows [1] czyli krótki przewodnik po dokumentacji, w kolejności od najważniejszych informacji, do najbardziej technicznych: README opis programu. główny plik dokumentacji. FAQ najczęściej zadawane pytania. jeśli masz jakiś problem, zajrzyj najpierw tutaj. wszelkie pytania, na które można tu znaleźć odpowiedź będą ignorowane, lub reakcja będzie złośliwa i nieprzyjemna. TODO lista rzeczy, które czekają w kolejce na realizację. jeśli chcesz napisać, że przydałaby się jakaś rzecz, najpierw zajrzyj tutaj. możliwe, że ktoś wcześniej zgłosił ,,zapotrzebowanie''. ChangeLog lista zmian w kolejnych wersjach. często zawiera informacje ważne, a nie wymienione w innych plikach. libgadu.txt informacja na temat instalacji i użycia libgadu ui-ncurses.txt opis interfejsu ncurses oraz ustawień/możliwości występujących wyłącznie w tym interfejsie. vars.txt opis zmiennych używanych przez program. mysz.txt obsługa myszy slownik.txt obsługa słownika aspell addons.txt krótki opis korzystania z niektórych usług obecnych w Gadu-Gadu a (celowo) nie zaimplementowanych w ekg. files.txt opis formatów plików: listy kontaktów, konfiguracji, historii, emotikonów. emoticons.ansi emoticons.sample przykładowe emoticony dcc.txt opis wykorzystania bezpośrednich połączeń do przesyłania plików. ich obsługa nie jest jeszcze kompletna i ma prawo działać nieprawidłowo. dodatkowo zawiera opis api kodu. voip.txt informacja na temat konfiguracji rozmów głosowych sim.txt wskazówki dotyczące korzystania z szyfrowania wiadomości. themes.txt opis dotyczący zmiany wyglądu klienta. przydatny dla tych, którzy lubią bawić się w kolorki. gdb.txt szybki kurs obsługi gdb. python.txt krótki opis możliwości obsługi skryptów w pythonie przez ekg. devel-hints.txt wskazówki dla tych, którzy chcą coś poprawić w ekg/libgadu. przenosny-kod.txt kilka wskazówek na temat pisania kodu przenośnego między różnymi uniksami. ui.txt wskazówki dla developerów chcących dodać nowe ui. [1] autor Jacek Popławski, $Id$ ekg-1.9~pre+r2855/docs/addons.txt000066400000000000000000000023301174410337000165560ustar00rootroot00000000000000// Obsługa usług dodanych do Gadu-Gadu // Copyright (C) 2007-2008 Adam Wysocki 1. Dlaczego? 2. Nagłos 3. Nowości 1. Dlaczego? Ponieważ chcielibyśmy uniknąć przeładowania ekg usługami nie związanymi bezpośrednio z komunikacją przez Gadu-Gadu. Z drugiej strony pewne usługi są dodawane do Gadu-Gadu i ktoś mógłby chcieć z nich skorzystać. Jeżeli do Gadu-Gadu zostanie wprowadzona jakaś nowa usługa, z której da się korzystać pod uniksami, ale z różnych przyczyn (głównie niechęci do zrobienia z ekg kobyły) nie chcemy implementować jej w ekg, to opis jej uruchomienia pojawi się w tym pliku. 2. Nagłos Oryginalny komunikator umożliwia komunikację głosową przy pomocy usługi pod nazwą "Nagłos". Baseciq na swojej stronie opisał sposób wykorzystania tej funkcjonalności przy pomocy Asteriska: http://www.baseciq.org/voip/asterisk/naglos.html 3. Nowości Oryginalny komunikator udostępnia feed RSS z informacjami, nowościami, reklamami itd. Gdyby ktoś był zainteresowany czytaniem tych informacji, to feed znajdzie pod adresem: http://rss.gadu-gadu.pl/nowosci.xml Feed kodowany jest przy pomocy CP-1250, więc należy przekodować go na odpowiednie dla siebie kodowanie (np. przy pomocy iconv). // $Id$ ekg-1.9~pre+r2855/docs/dcc.txt000066400000000000000000000046311174410337000160450ustar00rootroot00000000000000// bezpośrednie połączenia między klientami (dcc) w ekg aby umożliwić przesyłanie plików i rozmowy głosowe należy wykonać następujące komendy: set dcc 1 set dcc_ip reconnect jeśli jesteśmy za maskaradą lub chcemy przesyłać pliki do ludzi z tej samej sieci lokalnej, podajemy adres komputera widoczny od strony sieci. w przeciwnym wypadku podajemy adres zewnętrzny. jeśli mamy tylko jeden interfejs sieciowy, problemu nie ma, bo adres jest tylko jeden. zamiast adresu można wpisać tekst ,,auto''. w takim wypadku ekg ustawi adres, z którego wychodzi połączenie do serwera. po ponownym połączeniu możemy korzystać z dobrodziejstw bezpośrednich połączeń. jeśli ktoś spróbuje coś do nas wysłać, pojawi się: ->- ktoś/123 przesyła plik zdjecie.jpg o rozmiarze 129117 ->- Wpisz dcc get #1, by go odebrać, lub dcc close #1, by anulować wystarczy zastosować się do podanych wskazówek. jeśli chcemy wysłać komuś plik, wpisujemy: dcc send szczegóły dotyczące rozmów głosowych znajdują się w pliku ,,voip.txt''. należy pamiętać, że do przesyłania plików obie strony muszą mieć dopisane siebie do list kontaktów. jeśli ustawimy niewłaściwy adres, oryginalne klienty Gadu-Gadu będą odrzucać połączenia. dzieje się tak, gdy adres z którego przychodzi połączenie jest inny niż ten, który został przesłany przez serwer. ma to wpływ głównie na sytuacje typu: ,-----------. | Gadu-Gadu | workstacja `-----+-----' | | | | 10.0.0.5 `------+---+------+--------' | (sieć lokalna) | 10.0.0.1 ,----+----. | ekg | router z NAT `----+----' | 1.2.3.4 | (internet) jeśli ekg na routerze będzie miało ustawiony adres 1.2.3.4, taki adres zobaczy też serwer. ten sam adres dostanie klient Gadu-Gadu w sieci lokalnej. tyle że kiedy ekg będzie chciało wysłać plik do Gadu-Gadu, połączy się z adresu 10.0.0.1, bo taki ma przypisany do sieci lokalnej. w takim wypadku Gadu-Gadu odrzuci połączenie ze względu na niezgodność adresów. dlatego można albo ustawić adres sieci lokalnej, albo użyć do wysyłania: dcc rsend które wyśle do Gadu-Gadu żądanie połączenia za pośrednictwem serwera Gadu-Gadu i windowsowy klient sam się z nami połączy. ekg domyślnie odrzuci połączenie z innego adresu, ale można zmienić to zachowanie zmienną ,,dcc_filter''. $Id$ ekg-1.9~pre+r2855/docs/devel-hints.txt000066400000000000000000000052601174410337000175350ustar00rootroot00000000000000parę wymagań i wskazówek dla developerów: 1) gdy coś poprawiasz/dodajesz, zachowuj styl reszty kodu. wcięcia rób znakami tabulacji, a nie spacjami. stawiaj spacje po przecinkach i średnikach. jeśli masz inny styl, a podesłane poprawki będą dobre i/lub potrzebne, nie zdziw się, jeśli Twój kod zostanie przeredagowany. 2) dopisuj się do copyrightów na początku pliku. inaczej zakładam, że zrzekasz się praw do podesłanych kawałków kodu. oczywiście podsyłany kod musi być na takiej samej licencji, co reszta. w innym wypadku nie trać czasu i go nie przysyłaj. 3) zachowuj przyjętą konwencję. jeśli wszystkie zmienne danej struktury mają nazwy typu ,,foobar_count'', nie dodawaj ,,foocount'', czy ,,nfoo''. 4) nie zmieniaj api bez powodu. nawet jeśli chcesz to zrobić, skonsultuj z resztą developerów. 5) tworząc większy kawałek/moduł/plik przeznaczony do jakiejś konkretnej funkcji, staraj się nazywać funkcje i zmienne tak, by było wiadomo, do czego służą. przykład: funkcje dotyczące list zaczynają się list_*, funkcje dotyczące userlisty to userlist_*, konfiguracja to config_*. 6) do alokacji pamięci używaj funkcji xmalloc(), xcalloc(), xrealloc() i xstrdup(). nie musisz sprawdzać zwracanej wartości. jeśli zabraknie pamięci, funkcje te same zajmą się grzecznym zamknięciem programu. dbaj o zwalnianie buforów, gdy nie są one już potrzebne. zamiast strncpy() oraz strncat() używaj strlcpy() i strlcat(), które przyjmują jako parametr całkowity rozmiar bufora. nie trzeba się martwić o to, ile w buforze pozostało jeszcze miejsca, czy znak zerowy się zmieści, etc. obie funkcje _zawsze_ zwracają ilość znaków, jaka została(by) zapisana do bufora. 7) jeśli nie masz pojęcia o alokacji pamięci i obsłudze stringów w C, najlepiej daj sobie spokój. nawet jeśli kod działa, ale nie trzyma się kupy, zostanie odrzucony. 8) podsyłając patche, twórz je poleceniem ,,diff -u''. diff bez parametrów generuje patche, które nie zawierają żadnego kontekstu i ciężko je dołączyć do źródła, gdy zmieniła się wcześniej chociaż jedna linijka. patche najlepiej generować względem najświeższej wersji, ale nie jest to wymagane, jeśli w międzyczasie nie było poważnych zmian w kodzie. 9) jeśli poprawka jest niewielka (jedna, dwie linijki), nie trać swojego, ani mojego czasu, tylko po prostu wklej oryginał i poprawioną wersję do treści listu. nikt nie będzie się zachowywać tak, że będzie wrzucać do źródeł tylko to, co mu się podoba, albo tylko patche ludzi, z którymi piwo pija. byle tylko były zachowane pewne zasady i nie było po miesiącu bałaganu w kodzie. oczywiście wszystkie zmiany będą przeglądane i w razie czego autor dostanie po łapach. $Id$ ekg-1.9~pre+r2855/docs/ekg.man.en000066400000000000000000000032431174410337000164150ustar00rootroot00000000000000.TH EKG 1 "11 November 2002" .SH NAME ekg \- A Gadu-Gadu compatible client. .SH SYNOPSIS .B ekg [ .BI options .B ] .B [ .BI commands .B ] .SH DESCRIPTION .B ekg is an experimental Gadu-Gadu client. .SH OPTIONS .TP .BI \-h\ [\-\-help] Shows command line options. .TP .BI \-u\ username\ [\-\-user\ username] Starts ekg with other \"user profile\". By default config files are stored in ~/.gg/ (if there is a non-empty $CONFIG_DIR environment variable, ~/$CONFIG_DIR/gg/ is used instead); this option gives ability to create subdirectories structure with other setups. .TP .BI \-t\ theme\ [\-\-theme\ theme] Loads theme from the specified file. .TP .BI \-c\ file\ [\-\-control-pipe\ file] Creates a named pipe that can be used to control the client. .TP .BI \-o\ [\-\-no-pipe] Disables named pipe creation. .TP .BI \-n\ [\-\-no-auto] Don't connect automagically. After starting program won't automatically connect to the gg servers. .TP .BI \-N\ [\-\-no-global-config] Don't load global configuration file (i.e. /etc/ekg.conf) after user's one. .TP .BI \-a\ [\-\-away[=description]] After connecting sets the status to "away". .TP .BI \-b\ [\-\-back[=description]] After connecting sets the status to "back". .TP .BI \-F\ [\-\-ffc[=description]] After connecting sets the status to "free for chat". .TP .BI \-d\ [\-\-dnd[=description]] After connecting sets the status to "do not disturb". .TP .BI \-i\ [\-\-invisible[=description]] After connecting sets the status to "invisible". .TP .BI \-p\ [\-\-private] After connecting change to "private mode". .TP .BI \-v\ [\-\-version] Prints the client and libgadu library version. .TP .BI \-f\ name\ [\-\-frontend\ name] Selects given user interface. ekg-1.9~pre+r2855/docs/ekg.man.pl000066400000000000000000000033321174410337000164250ustar00rootroot00000000000000.TH EKG 1 "11 listopada 2002" .SH NAZWA ekg \- Eksperymentalny Klient Gadu-Gadu .SH SKŁADNIA .B ekg [ .BI opcje .B ] .B [ .BI komendy .B ] .SH OPIS .B ekg jest eksperymentalnym klientem Gadu-Gadu. .SH OPCJE .TP .BI \-h\ [\-\-help] Wyświetla listę możliwych opcji. .TP .BI \-u\ username\ [\-\-user\ username] Pozwala na uruchomienie ekg z innym ,,profilem użytkownika''. Standardowo konfiguracja ekg znajduje sie w katalogu ~/.gg/ (chyba, że zdefiniowana jest zmienna środowiskowa $CONFIG_DIR - wtedy w ~/$CONFIG_DIR/gg/). Ta opcja pozwala na stworzenie struktury podkatalogów z oddzielnymi konfiguracjami. .TP .BI \-t\ theme\ [\-\-theme\ theme] Ładuje motyw z podanego pliku. .TP .BI \-c\ plik\ [\-\-control-pipe\ plik] Tworzy nazwany potok (ang. named pipe) umożliwiający sterowanie klientem. .TP .BI \-o\ plik\ [\-\-no-pipe] Nie tworzy nazwanego potoku. .TP .BI \-n\ [\-\-no-auto] Nie łącz się automagicznie. Po uruchomieniu nie łączy się automatycznie z serwerami gg. .TP .BI \-N\ [\-\-no-global-config] Nie czytaj globalnego pliku konfiguracyjnego (np. /etc/ekg.conf) po wczytaniu pliku konfiguracyjnego użytkownika. .TP .BI \-a\ [\-\-away[=opis]] Po połączeniu zmienia stan na ,,zajęty''. .TP .BI \-b\ [\-\-back[=opis]] Po połączeniu zmienia stan na ,,dostępny''. .TP .BI \-F\ [\-\-ffc[=opis]] Po połączeniu zmienia stan na ,,poGGadaj ze mną''. .TP .BI \-d\ [\-\-dnd[=opis]] Po połączeniu zmienia stan na ,,nie przeszkadzać''. .TP .BI \-i\ [\-\-invisible[=opis]] Po połączeniu zmienia stan na ,,niewidoczny''. .TP .BI \-p\ [\-\-private] Po połączeniu włącza tryb ,,tylko dla przyjaciół''. .TP .BI \-v\ [\-\-version] Wyświetla wersję klienta i biblioteki libgadu. .TP .BI \-f\ nazwa\ [\-\-frontend\ nazwa] Wybiera podany interfejs użytkownika. ekg-1.9~pre+r2855/docs/ekglogs.man.en000066400000000000000000000023441174410337000173030ustar00rootroot00000000000000.TH EKGLOGS 1 "7 September 2003" .SH NAME ekglogs \- a logs lister for EKG .SH SYNTAX .B ekglogs [ .BI options .B ] < .B ~/.gg/history .SH DESCRIPTION .B ekglogs reads ekg logs on standard input and prints them out nicely formatted on standard output. .SH OPTIONS .TP .BI \-t don't display time at all .TP .BI \-d don't display day changes .TP .BI \-x always print nicknames .TP .BI \-v never display nicknames (by default: print nicknames unless either `u' or `n' was specified) .TP .BI \-r display incoming messages' receipt time .TP .BI \-R like \fB\-r\fR and align outgoing messages .TP .BI \-s display seconds .TP .BI \-S display receipt time seconds .TP .BI \-C display a colon between hours and minutes .TP .BI \-b do not display malformed lines (they start with !!!) .TP .BI \-a do not display status changes .TP .BI \-c use colourful display .TP .BI \-h display help message .TP .BI \-u\ UIN display only messages from/to \fIUIN\fR .TP .BI \-n\ NICK display only messages from/to \fINICK\fR .PP Options don't need to be preceded with `-', and may be concatenated. .PP Option `u' or `n' should be specified as last one. You should not specify both `u' and `n'. .SH AUTHOR Robert Goliasz .SH "SEE ALSO" .BR ekg (1) ekg-1.9~pre+r2855/docs/ekglogs.man.pl000066400000000000000000000023671174410337000173210ustar00rootroot00000000000000.TH EKGLOGS 1 "7 września 2003" .SH NAZWA ekglogs \- program do wypisywania historii rozmów EKG .SH SKŁADNIA .B ekglogs [ .BI opcje .B ] < .B ~/.gg/history .SH OPIS .B ekglogs pobiera logi ekg ze standardowego wejścia i wypisuje je w ładnej formie na standardowe wyjście. .SH OPCJE .TP .BI \-t nie wyświetlaj w ogóle czasu .TP .BI \-d nie wyświetlaj zmiany dni .TP .BI \-x zawsze wyświetlaj ksywkę .TP .BI \-v nigdy nie wyświetlaj ksywki (domyślnie: wyświetlaj jeśli nie podano opcji `u' ani `n') .TP .BI \-r wyświetlaj czas odebrania w wiadomościach przychodzących .TP .BI \-R j/w i wyrównaj wiadomości wychodzące .TP .BI \-s wyświetlaj sekundy .TP .BI \-S wyświetlaj sekundy przy czasie odebrania .TP .BI \-C wyświetlaj dwukropek między godziną a minutą .TP .BI \-b nie wyświetlaj błędnych linijek (zaczynają się od !!!) .TP .BI \-a nie wyświetlaj zmian statusu .TP .BI \-c wyświetlaj kolorki .TP .BI \-h wyświetl krótką pomoc .TP .BI \-u\ UIN pokazuj tylko wiadomości od/do \fIUIN\fR .TP .BI \-n\ NICK pokazuj tylko wiadomości od/do \fINICK\fRa .PP Opcji nie trzeba poprzedzać `-', można je łączyć lub nie. .PP Opcje `u' oraz `n' powinny być na końcu i nie powinny występować razem .SH AUTOR Robert Goliasz .SH "PATRZ TAKŻE" .BR ekg (1) ekg-1.9~pre+r2855/docs/ekl2.man.en000066400000000000000000000016501174410337000165040ustar00rootroot00000000000000.TH EKL2 1 "2 March 2003" .SH NAME ekl2 \- EKG history viewer. .SH SYNTAX .B ekl2 [ .BI OPTIONS .B ] [ .BI SOURCE .B ] .SH SUMMARY .B ekl2 This program prints the conversation history file as created by ekg. .SH OPTIONS .TP .BI \-d\ +format\ \-\-date\ +format\ Sets format of displayed date (see date(1)) .TP .BI \-\-location Sets log files' location (~/.gg/history by default) .TP .BI \-h\ \-\-help\ Prints help message. .TP .BI \-L\ \-\-List\ Prints the list of available log files. (from ~\/.gg\/history) .TP .BI \-l\ \-\-sessions\ [+num]\ [+off] Prints the list of sessions in given log file. .BI num\ is the number of session to display. .BI off\ is the offset between conversations, in minutes (60 by default). .TP .BI \-n\ \-\-nocolor\ No colors. .TP .BI \-sh\ \-\-short\ simplified form. .TP .BI \-v\ \-\-version\ Prints script version. .TP .BI SOURCE\ gg number, nickname or logfile name. .SH "SEE ALSO" .BR ekg (1). ekg-1.9~pre+r2855/docs/ekl2.man.pl000066400000000000000000000020321174410337000165100ustar00rootroot00000000000000.TH EKL2 1 "2 Marca 2003" .SH NAZWA ekl2 \- Podgląd historii Eksperymentalnego Klienta Gadu-Gadu. .SH SKŁADNIA .B ekl2 [ .BI OPCJE .B ] [ .BI ŹRÓDŁO .B ] .SH OPIS .B ekl2 Jest to aplikacja umożliwiająca podgląd historii rozmów, tworzonej przez Eksperymentalnego Klienta Gadu-Gadu. .SH OPCJE .TP .BI \-d\ +format\ \-\-date\ +format\ Ustala format wyświetlanej daty (zobacz date(1)). .TP .BI \-\-location\ Ustala miejsce przechowywania plików dziennika (domyślnie ~/.gg/history). .TP .BI \-h\ \-\-help\ Wyświetla pomoc. .TP .BI \-L\ \-\-List\ Pokazuje listę dostępnych logow. (z katalogu ~/.gg/history). .TP .BI \-l\ \-\-sessions\ [+num]\ [+ods] Pokazuje listę sesji w podanym logu. Nieobowiązkowy parametr .BI num\ to numer sesji, która ma zostać wyświetlona, a .BI ods\ to odstęp między rozmowami, w minutach (domyślnie: 60) .TP .BI \-n\ \-\-nocolor\ Bez kolorków. .BI \-sh\ \-\-short\ simplified form. .TP .BI \-v\ \-\-version\ Prints script version. .TP .BI ŹRÓDŁO\ numer gg, nick lub nazwa pliku z logami. .SH "PATRZ TEŻ" .BR ekg (1). ekg-1.9~pre+r2855/docs/emoticons.ansi000066400000000000000000000012411174410337000174210ustar00rootroot00000000000000<śpię> |-) :-* :-) :,-( 8-0 :-O  qp !!! (@)-,-'-- @-3- =|= \_/ c" OK! SHIT! _[]||| _[]||| ()"  ===O=== ~/ [STOP] ekg-1.9~pre+r2855/docs/emoticons.sample000066400000000000000000000003711174410337000177530ustar00rootroot00000000000000<śpię> |-) :-* :,-( 8-0 :-O @-,-'-- @-`-,-- OK! S*IT! _[=] ekg-1.9~pre+r2855/docs/files.txt000066400000000000000000000130071174410337000164130ustar00rootroot00000000000000Spis treści: 1. Format listy kontaktów ekg 2. Format konfiguracji ekg 3. Format konfiguracji zapisanej na serwerze 4. Format historii ekg 5. Format emotikon (Adam Osuchowski ) * * * 1. Format listy kontaktów ekg Lista kontaktów z pliku ,,userlist'' jest tego samego formatu co eksportowana z windowsowego klienta: imię;nazwisko;pseudonim;wyświetlana_nazwa;telefon;grupy;numer;email ekg może dopisać użytkownika do kilku metagrup: __blocked - użytkownik blokowany __offline - jesteśmy niedostępni dla użytkownika __ignored_ - użytkownik jest ignorowany z danym poziomem __ignored - wszystkie zdarzenia związane z użytkownikiem są ignorowane * * * 2. Format konfiguracji ekg Plik konfiguracyjny ,,config'' zawiera kolejne wpisy postaci: set bind alias on Jeśli pierwszy wyraz nie jest jednym ze znanych, jest traktowany jako nazwa zmiennej, po której występuje jej wartość -- chodzi o zachowanie kompatybilności z innymi klientami. Jeśli wartość zmiennej zaczyna się od znaku o kodzie 1, to następująca po nim wartość zmiennej jest zakodowana używając base64. * * * 3. Format konfiguracji zapisanej na serwerze Jeśli użytkownik umieści na serwerze również konfigurację, wszystkie zmienne (oprócz ,,uin'' i ,,password'', bo te nie są wysyłane) zostaną zapisane w skróconej postaci. Każda zmienna jest opisana przez swoją dwuliterową nazwę (nie można używać cyfr). Jeśli zmienna jest zmienną liczbową, zaraz po nazwie umieszcza się jej wartość, a za nią kolejną zmienną. Jeśli zmienna jest tekstowa i jest pusta, po nazwie umieszczany jest minus ,,-'' i za nim kolejna zmienna. Jeśli pierwszy znak zmiennej tekstowej jest plusem ,,+'', zawartość zmiennej została zakodowana w base64 i kończy się znakiem dwukropka ,,:''. Jeśli pierwszym znakiem nie jest plus, treść zmiennej znajduje się zaraz za nazwą i również kończy się dwukropkiem. Po dwukropku znajduje się kolejna zmienna. Widać zatem, że zmienne, w których występuje dwukropek lub średnik, albo zaczynają się od plusa, muszą zostać zakodowane w base64. Oto przykłady: dc1di127.0.0.1:ts+JUg6JU0gAA==:qr- dc (display_color) = 1 di (dcc_ip) = "127.0.0.1" ts (timestamp) = "%H:%M " qr (quit_reason) = (brak) Tak zapisana lista zmiennych jest umieszczana w oddzielnych wpisach listy kontaktów. Zamiast imienia jest ,,__config'', gdzie jest kolejną liczbą, ale w rzeczywistości nie ma większego znaczenia. Lista zmiennych jest dzielona po 24 znaki i umieszczana w pięciu kolejnych polach listy kontaktów. w ostatnim polu znajduje się losowa liczba udająca numerek osoby. Przy odbiorze nie ma znaczenia liczba po ,,__config'', nie ma znaczenia podział na kolejne pola. Wszystko jest i tak sklejane w jeden ciąg znaków i dopiero potem analizowane. * * * 4. Format historii ekg W zależności od ustawienia klienta, historia może być umieszczona w pojedynczym pliku (domyślnie ~/.gg/history) lub w osobnych plikach, po każdym na osobny numerek rozmówcy (domyślnie ~/.gg/history/). Pliki mogą być skompresowane za pomocą gzip -- w takim wypadku mają rozszerzenie ,,.gz''. Wpisy są w formacie CSV, tj. każdy wpis znajduje się w oddzielnej linii, a jego poszczególne kolumny są oddzielone przecinkami. Jeżeli któraś kolumna zawiera znak przecinka, nowej linii, cudzysłów, backslash, to cała zawartość kolumny zostaje ujęta w cudzysłów i zapisana jak ciąg znaków języka C. Możliwe wpisy to: - wysyłana wiadomość lub rozmowa: chatsend,,,, msgsend,,,, - odebrana wiadomość lub rozmowa: chatrecv,,,,, msgrecv,,,,, - ignorowana wiadomość lub rozmowa, gdy włączono opcję log_ignored: chatrecvign,,,,, msgrecvign,,,,, - zmiana stanu: status,,,[:port],, status,,,[:port],,, gdzie: - - numer nadawcy, odbiorcy lub osoby zmieniającej stan, - - pseudonim osoby, - - domyślnie ilość sekund od 1 stycznia 1970r. UTC, ale użytkownik może zmienić format tego pola za pomocą zmiennej log_timestamp, - - jeśli jest nieznany, zapisuje się ,,0.0.0.0'', - - jeden z ,,avail'', ,,busy'', ,,invisble'' i ,,notavail''. * * * 5. Format emotikon (Adam Osuchowski ) Za pomocą oryginalnego klienta GG można wysłać sekwencje znakowe, które będą się zamieniać na odpowiednie ikony. Z oczywistych względów w ekg wykonać się tego nie da (może ktoś kiedyś zrobi wsparcie dla aaliba ;))). Sekwencje te, zamieniane są więc na inne sekwencje. Np. sekwencja: może być zamieniona na: :-* lub podobną, wedle uznania użytkownika. Aby skorzystać z możliwości rozwijania tego typu makr w otrzymywanych wiadomościach, należy je sobie wcześniej zdefiniować. Robi się to w pliku ~/.gg/emoticons. Każda linia tego pliku definiuje jedno makro, a jej format jest następujący: Należy zwrócić uwagę na to, że do oddzielenia emoticonu od jego rozwinięcia służą tylko i wyłącznie tabulatory (jeden lub więcej). Spowodowane jest to występowaniem spacji w oryginalnych GG-owych emoticonach. Przykładowy zestaw definicji można znaleźć w docs/emoticons.sample. Nie zawiera on wszystkich definicji, bo nie miałem na tyle inwencji, żeby je powymyślać. :)) $Id$ ekg-1.9~pre+r2855/docs/gdb.txt000066400000000000000000000033711174410337000160500ustar00rootroot00000000000000// szybki kurs obsługi gdb // (c) copyright 2002 wojtek kaniewski jeśli program się wywrócił i utworzył plik core, za pomocą gdb można sprawdzić, w którym miejscu wystąpił błąd. najpierw uruchamiamy gdb: $ gdb ekg ~/.gg/core GNU gdb 5.0 (UI_OUT) Copyright 2000 Free Software Foundation, Inc. (...) #0 command_test_segv (name=0x80617c9 "_segv", params=0x8088c20) at commands.c:1601 1601 return (*foo = 'A'); (gdb) od razu widzimy, że błąd wystąpił w funkcji ,,command_test_segv'' z pliku commands.c. potem widzimy błędną linię. w niektórych przypadkach niestety to nie wystarcza. możliwe, że linia, w której wystąpił błąd jest poprawna, ale dostarczone dane nie były właściwe. wtedy z pomocą przychodzi polecenie ,,bt'', które wyświetla stos wywołań funkcji. widzimy dzięki temu po kolei, jaka funkcja wywoływała jaką funkcję i z jakimi parametrami: (gdb) bt #0 command_test_segv (name=0x80617c9 "_segv", params=0x8088c20) at commands.c:1601 #1 0x080506e2 in old_execute (target=0x0, line=0x0) at commands.c:2009 #2 0x08050980 in ekg_execute (target=0x0, line=0x806d700 "_segv") at commands.c:2136 #3 0x08059192 in ui_ncurses_loop () at ui-ncurses.c:231 #4 0x080578d8 in main (argc=1, argv=0xbffffb24) at ekg.c:726 #5 0x4008e38f in __libc_start_main () from /lib/libc.so.6 teraz widzimy, że po prostu użytkownik wywołał komendę ,,_segv''. co prawda widać to po samej nazwie funkcji, w której wystąpił błąd, ale w większości przypadków nie będzie to aż tak oczywiste. niestety zdarza się i tak, że błędny kod narusza ważne obszary pamięci, a sam błąd występuje później, chociażby przy wywoływaniu funkcji alokacji pamięci. w takich przypadkach zlokalizowanie błędu jest znacznie trudniejsze. $Id$ ekg-1.9~pre+r2855/docs/libgadu.txt000066400000000000000000000030341174410337000167170ustar00rootroot00000000000000// $Id$ // (C) 2007-2008 Adam Wysocki Od 5 lipca 2007 biblioteka libgadu, odpowiedzialna za komunikację, oraz klient ekg, rozwijane i rozpowszechniane są oddzielnie. Żeby zainstalować ekg, należy najpierw zainstalować libgadu. - Jeżeli korzystasz ze snapshotów (pobrałeś ekg ze strony www): - cd libgadu (będąc w katalogu z ekg) - ./configure (opcjonalne parametry, jak --prefix=katalog-domowy) - make - make install (jeżeli instalujesz systemowo, to z uprawnieniami roota) - Jeżeli korzystasz z SVN: - svn co http://toxygen.net/svn/libgadu/trunk libgadu - cd libgadu - ./autogen.sh (opcje jak przy ./configure) - make - make install Jeżeli nie zainstalowałeś libgadu systemowo (tylko np. w katalogu domowym), to przed wykonaniem ./configure w katalogu ekg musisz podać ścieżkę do plików nagłówkowych oraz biblioteki libgadu: ./configure "CFLAGS=-I ścieżka_do_include" "LDFLAGS=-L ścieżka_do_lib" Przykładowo: ./configure "CFLAGS=-I $HOME/libgadu/include" "LDFLAGS=-L $HOME/libgadu/lib" Ponadto przed uruchomieniem ekg będzie potrzebne ustawienie ścieżki dla loadera: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:ścieżka_do_lib Przykładowo: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/libgadu/lib Najlepiej wstawić tą linijkę do .bashrc lub odpowiedniego pliku uruchamianego przez powłokę przy starcie (w zależności od powłoki eksportowanie zmiennych może odbywać się w inny sposób - należy sprawdzić w dokumentacji powłoki). Pytania, skargi i wnioski: http://ekg.chmurka.net/kontakt.php ekg-1.9~pre+r2855/docs/mysz.txt000066400000000000000000000216371174410337000163230ustar00rootroot00000000000000// obsluga myszy w ekg // (c) 2006 adam wysocki 1. wstep 2. aktualne bindingi 3. terminologia 4. struktury i typy danych 5. rozpoznawane zdarzenia przyciskow 6. interfejs 7. przyklad uzycia 8. do zrobienia 1. wstep obsluga myszy w ekg jest na razie wstepnym, eksperymentalnym frameworkiem do dalszego obudowania, dzialajacym tylko w interfejsie ncurses. ten plik zawiera opis aktualnych bindingow (czyli obszarow, w ktore mozna kliknac lub na ktorych mozna wykonac gesty) oraz developerski opis, przydatny podczas dodawania obslugi myszy do kolejnych elementow ekg. gdyby cos z niego bylo nie do konca jasne albo dwuznaczne, nalezy napisac na ekg-users (adres znajduje sie na stronie ekg). poprawki mile widziane. jesli nie jestes zainteresowany rozwijaniem obslugi myszy w ekg, a jedynie jej uzywaniem, to rozdzial "aktualne bindingi" jest jedynym, ktory powinienes przeczytac. 2. aktualne bindingi aktualne przyporzadkowania zdarzen myszy. gest to przesuniecie myszy podczas trzymania ktoregos przycisku. jesli nie zostalo okreslone inaczej, gest mozna wykonac trzymajac lewy lub prawy przycisk. lpm to lewy przycisk myszy, ppm - prawy. obszar | zdarzenie | polecenie lub opis ------------------------+-----------------------+------------------- header | klikniecie | /list header | podwojne klikniecie | /find statusbar: zegar | klikniecie | /exec ^date statusbar: uin, nick | klikniecie | /status statusbar: uin, nick | prawe klikniecie | /find statusbar: query | klikniecie | /list $ statusbar: query | prawe klikniecie | /find $ statusbar: more | klikniecie | Page Down statusbar: win/numer | klikniecie | /window list $ statusbar: act/numer | klikniecie | /window list statusbar: act/numer | podwojne klikniecie | /window switch rozmowa | gest w lewo | /window prev rozmowa | gest w prawo | /window next rozmowa | gest w gore | /window last rozmowa | gest w dol z lpm | /window oldest rozmowa | gest w dol z ppm | /window active 3. terminologia - zdarzenie myszy (mouse_event): zmiana wartosci zmiennej mouse, zdarzenie przycisku myszy lub prosba o zwolnienie pamieci ze strukturami. NIE jest tozsame ze zdarzeniem myszy w man mouse z ncurses. wszystkie zdarzenia myszy sa obslugiwane w funkcji mouse_event(). - zdarzenie przycisku myszy (bevent): klikniecie, podwojne klikniecie, potrojne klikniecie, wcisniecie lub puszczenie przycisku. zdarzenia przyciskow myszy sa obslugiwane przez odpowiednio dodane handlery. - gest myszy: jest rozpoznawany, gdy przesuniemy mysz trzymajac ktorys przycisk. gesty stworzone zostaly na podstawie obslugi myszy w irssi (http://wouter.coekaerts.be/site/irssi/mouse) z ta roznica, ze kierunek jest obliczany nastepujaco: - odleglosc_x > 2 * odleglosc_y: kierunek poziomy - odleglosc_y > 2 * odleglosc_x: kierunek pionowy - pozostale: gest nierozpoznany 4. struktury i typy danych - mouse_area_t - opisuje jeden konkretny obszar na ekranie. obszar jest prostokatem zdefiniowanym przez polozenie lewego gornego rogu oraz szerokosc i wysokosc. struktura zawiera takze polozenie prawego dolnego rogu, ustawiane przez funkcje obslugi myszy. obszar moze, ale nie musi, miec taki sam rozmiar jak ktores okno (np. header albo statusbar). oprocz tego kazdy obszar ma swoja nazwe - przydatne do lepszej identyfikacji w oknie debugowania i podczas zmiany rozmiaru okna. - mouse_coords_t - struktura opisujaca koordynaty punktu na ekranie lub w obszarze. zawiera zmienne x (numer kolumny) i y (numer wiersza). lewy gorny rog ma koordynaty 0,0. - mouse_bevent_t - struktura na liscie w mouse_area_t. opisuje zdarzenie przycisku dla obszaru, do ktorego nalezy (wartosc zdarzenia okreslajaca, ze np. zostal podwojnie klikniety ktorys przycisk i wskaznik do handlera mouse_handler_t, ktory obsluzy to zdarzenie). - mouse_handler_t - wywolywane do obslugi zdarzenia. dostaje maske przycisku (mmask_t) i wskaznik do opisu koordynatow (mouse_coords_t). maska przycisku moze sie przydac, gdyby ktos chcial podpiac kilka zdarzen przycisku do jednego handlera (podobnie jak signo w sighandlerach). koordynaty mierzone sa wzgledem poczatku obszaru (a nie ekranu lub okna). handler niczego nie zwraca. 5. rozpoznawane zdarzenia przyciskow jak w man 3ncurses mouse: - BUTTONx_PRESSED: przycisk zostal wcisniety i jest trzymany - BUTTONx_RELEASED: przycisk zostal puszczony - BUTTONx_CLICKED: przycisk zostal klikniety - BUTTONx_DOUBLE_CLICKED: przycisk zostal podwojnie klikniety - BUTTONx_TRIPLE_CLICKED: przycisk zostal potrojnie klikniety x moze przyjmowac wartosci od 1 do 5 (dla NCURSES_MOUSE_VERSION == 1 tylko 4). dla normalnych myszek 1 to lewy, 2 srodkowy a 3 prawy przycisk. oprocz tego, jesli numer zdarzenia jest zORowany z BUTTON_CTRL, BUTTON_SHIFT lub BUTTON_ALT, oznacza to zdarzenie przy wcisnietym ktoryms z tych klawiszy. dodajac button eventy powinno sie pamietac, ze: - niektore terminale maja jakies alternatywne funkcje dla klikniec z ktoryms z klawiszy ctrl, shift lub alt i nie przekazuja takiego klikniecia do programu. - nie kazdy posiada srodkowy przycisk myszki lub emulacje przez wcisniecie obu przyciskow. 6. interfejs - mouse_event() - obsluguje zdarzenia myszy - mouse_bevent_add() - dodaje button event do obszaru - mouse_area_add() - dodaje obszar do listy - mouse_area_find() - znajduje obszar po nazwie - mouse_area_del() - usuwa obszar z listy - mouse_area_move() - przesuwa obszar - mouse_area_resize() - ustawia nowy rozmiar obszaru - mouse_in_area() - sprawdza czy punkt nalezy do obszaru wskazniki, ktore dostaja te funkcje, nie musza byc alokowane - moga wskazywac na obiekty lokalne dla wywolujacej funkcji. mouse_bevent_add() powinno byc wywolywane na lokalnej strukturze, a dopiero po wszystkich mouse_bevent_add() powinno zostac wywolane mouse_area_add(). mouse_area_resize() jest przydatne podczas zmiany rozmiaru okna, np. po dostaniu przez leb sigwinchem albo zmianie wartosci ktorejs zmiennej. 7. przyklad uzycia gdyby ktos chcial bardziej czytelnie, niz w zrodlach ekg, dla hipotetycznego obszaru "test": static void mouse_bevent_test (struct mouse_coords_t *coords, mmask_t bstate) { if (bstate == BUTTON1_CLICKED) { // ... } else if (bstate == BUTTON1_DOUBLE_CLICKED) { // ... } } ...() { struct mouse_area_t a; a.name = "test"; a.start.x = a.start.y = 0; a.size.x = a.size.y = 10; a.bevents = NULL; mouse_bevent_add(&a, BUTTON1_CLICKED, mouse_bevent_test); mouse_bevent_add(&a, BUTTON1_DOUBLE_CLICKED, mouse_bevent_test); mouse_area_add(&a); } nie trzeba sie troszczyc o zwalnianie niczego, mouse_event("destroy") zrobi to sama, jednak trzeba pamietac zeby przed pierwszym mouse_bevent_add() pole bevents bylo rowne NULL. pole name nie musi byc zaalokowane - zostanie zaalokowane przez mouse_area_add(). 8. do zrobienia - mozliwosc oskryptowania myszy w pythonie - mozliwosc bindowania beventow przez uzytkownika (/mouse_bind?) - -a: przypisanie akcji do pary obszar,zdarzenie - -d: usuniecie akcji dla podanej pary obszar,zdarzenie - [-l]: wylistowanie przypisanych akcji - -L: wylistowanie przypisanych oraz domyslnych akcji - konkurs na nazwe dla pary obszar,zdarzenie :) - definicje: - obszar (w nawiasie znaczenie parametru) - current (konkurs na lepsza nazwe dla obszaru current_window :)) - contacts ($1: nick) - header (naglowek jako calosc) - header:query_ip ($1: ip) - header:query_descr ($1: opis) - status (pasek stanu jako calosc) - status:time - status:uin - status:nick - status:more - status:query - status:window - status:act ($1: numer okna) - status:query_ip ($1: ip) - status:query_descr ($1: opis) - zdarzenie (przycisk-czynnosc) - przycisk - left - middle - right - czynnosc - click - double_click - triple_click - gesture_up - gesture_down - gesture_left - gesture_right - roll_up (przycisk ignorowany) - roll_down (przycisk ignorowany) - akcja - wszystkie akcje z /bind - komendy do wykonania (przyjmuja parametry) - moze obsluga masek, a nie tylko wartosci, w mouse_bevent_add()? - beventy dla listy kontaktow i paska stanu (jesli nie zaznaczono inaczej, to klikniecia): - lista: /list - lista: podwojne: /query - rolka: scrollowanie listy (może ogólnie też dla okna rozmowy?) - pasek: query_ip: /exec ^host - pasek: query_descr i inne odnosnie opisu: /list - pamietac o sigwinch i innych mozliwosciach (zmiany wartosci zmiennych, zdarzenia itd.) zmiany obecnosci, polozenia i rozmiaru obszarow. podczas dodawania obszaru do okna warto grepnac zrodla pod katem wystepowania odpowiednich funkcji z ncurses dla tego okna. jesli pozycja w oknie ma znaczenie to trzeba tez pilnowac, zeby opis pozycji poszczegolnych elementow byl aktualizowany // $Id$ ekg-1.9~pre+r2855/docs/protocol.html000066400000000000000000000010701174410337000172740ustar00rootroot00000000000000 Protokół Gadu-Gadu — zmiana adresu

Najnowsza wersja opisu protokołu znajduje się pod adresem http://toxygen.net/libgadu/protocol/.

ekg-1.9~pre+r2855/docs/przenosny-kod.txt000066400000000000000000000015261174410337000201360ustar00rootroot00000000000000kilka uwag co do przenośności kodu: 1) na systemach BSD ważna jest kolejność sieciowych #include'ów: #include #include #include #include 2) typy danych uintXX_t nie są dostępne na starszych platformach. na nowszych mogą wystąpić w , lub podobnych. najlepiej sprawdzić w configure, czy istnieją, a jeśli nie, zdefiniować je. 3) ,,__attribute__ ((packed))'' jest rozszerzeniem gcc, więc nie będzie dostępne na starszych platformach. 4) zachowanie snprintf() zmieniło się w C99. wcześniej zwracało -1, jeśli ciąg znaków był zbyt krótki, a teraz zwraca ilość bajtów, jaka byłaby zapisana do bufora, gdyby starczyło miejsca. 5) trzeba uważać na kolejność bajtów, jeśli pisze się lub czyta binarne wartości liczbowe z plików lub gniazd. $Id$ ekg-1.9~pre+r2855/docs/python.txt000066400000000000000000000101551174410337000166330ustar00rootroot00000000000000// obsługa skryptów w pythonie 1) ./configure --with-python 2) skrypty muszą znajdować się w ~/.gg/scripts 3) /help python 4) przykładowy skrypt: # skrypt ignorujący zmiany stanu zawierające w opisie coś, co # przypomina tytuł empetrójek. # # 20021215 wojtekka import ekg import re regulka = re.compile("^[A-Z].* - [A-Z].*") def init(): ekg.printf("generic", "Załadowano super hiper skrypciora!") return 1 def deinit(): ekg.printf("generic", "Ta-jest, kapitanie") def handle_status(uin, name, status, descr): if not descr: return 1 if regulka.match(descr): return 2 else: return 1 *** skrypty pythonowe w ekg mają być naprawdę proste w pisaniu, w przeciwieństwie do skryptów perlowych w irssi, które ciężko z początku zrozumieć. jest kilka funkcji, które będą wywoływane przez ekg w szczególnych przypadkach. jeśli któraś funkcja zwróci wartość 0, zdarzenie zostanie ignorowane, jeśli charakter zdarzenia na to pozwala (wiadomości, zmiany stanu itp.). jeśli zwróci 1, zdarzenie zostanie normalnie obsłużone przez ekg. jeśli zdarzenie wiąże się z wyświetleniem jakiegoś tekstu, zwrócenie wartości 2 powoduje ukrycie informacji o nim, ale zostanie ono obsłużone przez ekg. jeśli zdarzenie zwróci krotkę/entkę/cokolwiek (ang. tuple) o takim samym wyglądzie jak argumenty funkcji, informacje o zdarzeniu zostaną zmienione na podane. na przykład: def handle_msg(uin, name, msgclass, text, time, secure): if string.find(text, ":(((") != -1: text = "(zbyt smutny tekst, ukryto)" return (uin, name, msgclass, text, time, secure) return 1 oto lista wywoływanych funkcji: - init() gdy skrypt jest ładowany. jeśli ta funkcja zwróci 0, skrypt nie zostanie załadowany. - deinit() gdy skrypt jest usuwany z pamięci. - handle_msg(uin, name, msgclass, text, time, secure) gdy ekg otrzymuje wiadomość. uin - numer nadawcy, name - jego nazwa, msgclass - klasa wiadomości, text - treść, secure - czy mamy do czynienia z odszyfrowaną wiadomością. jeśli zwróci 0, wiadomość zostanie zignorowana. gdy zwróci 2, wiadomość nie zostanie wyświetlona na ekranie. jeśli zwróci krotkę/entkę/cokolwiek (ang. tuple) o takich samych argumentach jak funkcja, dane zostaną zmienione. - handle_msg_own(rcpts, text) gdy użytkownik wysyła wiadomość. rcpts jest _tekstową_ reprezentacją odbiorcy, dokładnie taką jak podał użytkownik (pierwszy argument /msg, /chat, /query itd). jeśli zwróci 0, wiadomość nie zostanie wysłana. - handle_status(uin, name, status, descr) gdy ktoś zmienia stan. nazwy parametrów powinny być zrozumiałe. jeśli zwróci 0, zmiana stanu zostanie zignorowana. jeśli zwróci 2, zmiana stanu nie będzie ignorowana, ale nie zostanie wyświetlona. jeśli zwróci krotkę o takich samych argumentach jak funkcja, dane zostaną zmienione. - handle_status_own(status, descr) gdy klient zmienia stan. jeśli zwróci 0, stan nie zostanie zmieniony. - handle_keypress(meta, key) gdy zostaje wciśnięty klawisz o kodzie key. jeśli wcześniejszym kodem był 27, meta jest równe 27. zwracane wartości pochodzą z funkcji getch() biblioteki ncurses, więc dla większości klawiszy funkcyjnych są zwracane odpowiednie kody. ich listę można znaleźć w plikach nagłówkowych ncurses w stałych z przedrostkiem KEY_ - handle_command_line(target, line) gdy wpisane zostanie linia w oknie ekg. target, jeśli nie puste, zawiera alias/uin użytkownika, z którym trwa rozmowa w aktualnym oknie. - handle_redraw_header() gdy należy odświeżyć nagłówek okna. - handle_redraw_statusbar() gdy należy odświeżyć pasek stanu. później zostaną dodane funkcje dotyczące wszystkich zdarzeń związanych z sesją gg, plus obsługa interfejsu użytkownika (informacja o wysłanej linii itp.) *** skrypty umieszczone w katalogu ~/.gg/scripts/autorun będą ładowane automagicznie przy starcie ekg. *** przykłady użycia modułu ekg w skryptach: ekg.printf("generic", "Jestem skryptem w Pythonie!") ekg.command("msg 123 hej!") ekg.disconnect() ekg.config.uin = 12345 ekg.config.password = "test123" ekg.connect() później dojdą funkcje wywoływania podstawowych komend typu ,,msg'' itp. obsługa okienek, themów, itd, itd. $Id$ ekg-1.9~pre+r2855/docs/sim.txt000066400000000000000000000023441174410337000161030ustar00rootroot00000000000000// Obsługa Secure Internet Messaging w ekg // (c) wojtekka Szyfrowanie to jest zgodne z http://gg.wha.la/crypt/ i powinno działać bez problemu z PowerGG i Kadu. Klucze są przechowywane w katalogu ~/.gg/keys w formacie PEM -- klucz prywatny w pliku ,,private.pem'', klucze publiczne w plikach odpowiadających numerowi rozmówcy z rozszerzeniem ,,.pem''. Aby wygenerować sobie klucz piszemy: key -g Zostanie on zapisany na dysku. Jeśli chcemy szyfrować wiadomości wysyłane do znajomych, musimy umieścić ich klucze publiczne w ~/.gg/keys. Jeśli chcemy, żeby wiadomości wysyłane do nas były szyfrowane, musimy wysłać naszym rozmówcom nasz klucz publiczny, używając polecenia ,,key -s''. NIE NALEŻY NIKOMU WYSYŁAĆ KLUCZA PRYWATNEGO Z PLIKU PRIVATE.PEM. By włączyć szyfrowanie, należy już tylko wpisać: set encryption 1 Dalej wszystko będzie się działo automagicznie. szyfrowane wiadomości są odpowiednio oznaczane -- domyślnie jest to żółty tekst ,,szyfrowane'' w nagłówku wyświetlanej wiadomości. ekg po otrzymaniu w wiadomości klucza publicznego (to znaczy wiadomości zaczynającej się od ,,-----BEGIN RSA PUBLIC KEY-----'') zapisze go jako klucz nadawcy w katalogu ~/.gg/keys. Zarządzanie kluczami odbywa się za pomocą polecenia ,,key''. $Id$ ekg-1.9~pre+r2855/docs/slownik.txt000066400000000000000000000017371174410337000170060ustar00rootroot00000000000000// Obsługa słownika aspell w EKG (http://ekg.chmurka.net) // (c) copyright 2004 Piotr Kupisiewicz Słownik do prawidłowego działania wymaga zainstalowanego aspell'a. Aby dowiedzieć się, jak zainstalować aspell'a dla Twojej wersji systemu operacyjnego odwiedź jego stronę domową. Strona domowa aspell'a to: http://aspell.net/ Polski słownik można znaleźć tutaj: http://ftp.gnu.org/gnu/aspell/dict/pl/ Jak skompilować i zainstalować aspell'a należy przeczytać tutaj: http://aspell.net/man-html/Installing.html Po prawidłowym zainstalowaniu słownika, należy skompilować ekg z obsługą aspell'a. Aby to zrobić, należy podczas kompilacji dodać przełącznik --enable-aspell jako parametr ./configure. Dalsza część instalacji wygląda tak samo (tj make && make install). Aspell w ekg działa tylko przy włączonych domyślnie ncurses. Wyrazy napisane nieprawidłowo są podkreślane. Linie zaczynające się od znaku "/" są ignorowane. Opisy zmiennych znajdują się w pliku vars.txt. ekg-1.9~pre+r2855/docs/themes.txt000066400000000000000000000054201174410337000165760ustar00rootroot00000000000000 .---------------,--------,-------,-----. | kolor | zwykły | jasny | tło | ,---------------+--------+-------+-----' | czarny/szary | %k | %K | %l | | niebieski | %b | %B | %e | | czerwony | %r | %R | %s | | fioletowy | %m/%p | %M/%P | %q | | turkusowy | %c | %C | %d | | brązowy/żółty | %y | %Y | %z | | zielony | %g | %G | %h | | biały | %w | %W | %x | | mrugający | %i | - | - | | tłusty | %T | - | - | ,---------------'--------'-------'-----| | bez koloru | %n | `---------------'----------------------' * * * przy %1-%9 można kazać dopełniać do konkretnej szerokości. przydaje się do wszelkiego rodzaju tabelek. %[10]1 dopełnia spacjami z prawej pierwszy parametr do 10 pól %[-10]1 j.w. tylko że do lewej %[.5]1 dopełnia zerami %[,9]2 dopełnia kropkami %[_4]1 dopełnia znakami podkreślenia %(10)1 jeśli rozmiar parametru przekroczy 10 znaków nie obcina UWAGA! kolorkowe sekwencje ansi traktuje jak znaki, więc nie powinno się ich używać przy dopełnianiu parametrów. * * * jeśli chce się rozróżniać przymiotniki dla różnych płci, można użyć %@n, gdzie ,,n'' to numer formatu, który bierzemy pod uwagę. jeśli ostatnią literą będzie ,,a'', %@n zostanie zastąpione przez ,,a'', w innym przypadku przez ,,y''. przykład: %> %1 jest dostępn%@1. należy wziąć uwagę, że w wielu wypadkach pseudonimy są najpierw formatowane przez known_user i unknown_user, więc trzeba podać osobny parametr z samym pseudonimem. * * * %> prompt (domyślnie zielony) %! error (domyślnie czerwony) %) prompt2 (domyślnie turkusowy) %# timestamp (domyślnie GG:MM) %| koniec promptu. jeśli ten format występuje, to przy przenoszeniu do następnej linii, tekst przed tym formatem zostanie wyświetlony ponownie. na przykład dla: %> Długa linia, która zostanie podzielona na kilka linii na małym terminalu zostanie podzielone na: .-------------------------. | ::: Długa linia, która | | zostanie podzielona na | | kilka linii | `-------------------------' a po dodaniu %|, tzn: %> %|Długa linia, która zostanie podzielona na kilka linii zostanie wyświetlone jako: .-------------------------. | ::: Długa linia, która | | ::: zostanie podzielona | | ::: na kilka linii | `-------------------------' * * * dwa specjalne formaty ,,known_user'' i ,,unknown_user'' określają, jak będą pokazywani userzy z listy i spoza listy kontaktów. pierwszy za parametry przyjmuje %1 opis, %2 numerek, a drugi %1 numerek. * * * wpisy readline_*, oprócz readline_prompt_query nie mogą zawierać żadnych ,,procentowych'' kodów sterujących. podobnie jest z promptem config_changed. * * * $Id$ ekg-1.9~pre+r2855/docs/ui-ncurses.txt000066400000000000000000000061471174410337000174150ustar00rootroot00000000000000// ui-ncurses // (c) copyright 2002 wojtek kaniewski interfejs ten różni się nieco od readline z okienkami. główną różnicą jest fakt, że pierwsze okienko istnieje _zawsze_ i jest oknem stanu. do niego lecą informacje o pojawianiu się i znikaniu ludzi. szczegóły dotyczące obsługi klawiatury znajdują się w pliku README. zalecane ustawienia: set display_ack 3 set display_sent 1 set make_window 2 pasek stanu zawiera zegar, informacje o własnym numerku (kolor określa stan: czarny -- niedostępny, biały -- dostępny, szary -- zajęty, ciemnoszary -- niewidoczny), numer aktualnego okna, informacje o aktywności w innych oknach, nowej poczcie itd. dodano nowy format ,,statusbar''. podobnie jak i reszta obsługuje kolory, ale nie ma dopełniania, mrugania itp. są za to konstrukcje warunkowe oraz rozszerzone informacje: %{time} aktualny czas formatu %H:%M %{uin} własny numer %{window} numer aktualnego okna %{query} rozmówca w aktualnym oknie %{activity} lista okien, w których się coś pojawiło %{nick} własny pseudonim %{descr} opis stanu %{mail} ilość nowej poczty lub pusty jeśli nie ma %{query_descr} opis stanu rozmówcy %{version} wersja ekg %{url} adres do strony ekg konstrukcje warunkowe pozwalają dodawać do pasku stanu teksty tylko, gdy spełniony zostanie określony warunek. konstrukcje te wyglądają następująco: %{?warunek tekst} tekst wyświetlony przy spełnionym warunku %{?!warunek tekst} tekst wyświetlony przy niespełnionym warunku warunkiem może być dostępność któregoś z wyżej wymienionych tekstów. jeśli na przykład w aktualnym oknie jest prowadzona rozmowa, warunek %{?query ...} będzie spełniony. jeśli nie skonfigurowaliśmy własnego numeru, spełniony będzie warunek %{?!uin ...}. ponadto występują również: %{?away ...} stan zajęty %{?avail ...} stan dostępny %{?notavail ...} stan niedostępny (niepołączony) %{?invisible ...} stan niewidoczny %{?more ...} dopisano coś do okna, gdy jest przewinięte %{?query_away ...} rozmówca zajęty %{?query_avail ...} rozmówca dostępny %{?query_notavail ...} rozmówca niedostępny %{?query_invisible ...} rozmówca niewidoczny warunki można zagnieżdżać, tzn. %{?query %{!?query_descr ...}} zostanie wyświetlone, jeśli prowadzona jest rozmowa, ale rozmówca nie ma stanu opisowego. domyślny format czasu (%{time}) można zmienić za pomocą wpisu ,,ncurses_timestamp''. szczegóły w stronie manuala strftime(3). dzięki temu można konstruować kosmiczne paski stanu. ale i tak domyślny powinien wystarczyć każdemu. jest możliwość rozszerzenia pasku stanu do maksymalnie 5-ciu linii. kolejne linie są opisane formatami ,,statusbar2'', ,,statusbar3'' itd. jeśli występuje format ,,statusbar1'', ma on pierwszeństwo przed ,,statusbar''. możliwe jest też włączenie nagłówka okna, tj. paska wyświetlanego u góry ekranu, nad oknami. jest on opisany formatami ,,header'', ,,header1'', ,,header2'' itd., analogicznie do paska stanu. dostępne formaty są identyczne. %| w pasku stanu lub nagłówku okna dopełnia do końca linii. przydatne, gdy zmieniamy kolor tła, ponieważ domyślnym kolorem jest niebieski. %} w pasku stanu lub nagłówku okna wyświetla znak '}' $Id$ ekg-1.9~pre+r2855/docs/ui.txt000066400000000000000000000051101174410337000157220ustar00rootroot00000000000000od 20020627 ekg jest przygotowane do obsługi różnych interfejsów użytkownika. przeprowadzono całkiem sporą reorganizację kodu, dzięki czemu nie trzeba będzie psuć zbyt dużo, żeby dodać jakikolwiek inny frontend. jeśli ktoś chce napisać własny interfejs (chociażby w gtk+, chociaż nie wiadomo po co, skoro jest GNU Gadu -- http://gadu.gnu.pl/), musi napisać ui-costam.c, zawierający poniżej podane funkcje i dopisać parę linijek do ekg.c. ui_costam_init() inicjalizacja interfejsu użytkownika. dla ui-readline będzie to ustawienie wszystkich zmiennych. dla ui-ncurses pewnie jakieś initscr(), przygotowanie okienek itd. należy przypisać zmiennym ui_post_init, ui_deinit, ui_print, ui_event, ui_loop, ui_beep adresy funkcji danego interfejsu. nawet jeśli funkcja nic nie robi, musi być zdefiniowana. zmiennym tym NIE WOLNO przypisać wartości NULL. należy też utrzymywać w zmiennych ui_screen_width oraz ui_screen_height aktualny rozmiar ekranu. ui_post_init() funkcja wywoływana po wczytaniu konfiguracji. ui_deinit() pozamykanie wszystkiego. ui_print(const char *target, int separate, const char *line) wyświetlenie tekstu ,,line'' w oknie ,,target''. przewidziano trzy specjalne okna -- ,,__status'' dla pierwszego okna statusowego, ,,__current'' dla aktualnego oraz ,,__debug'' dla okna z komunikatami dla developerów. parametr ,,separate'' mówi, czy wyświetlany tekst jest na tyle ważny, żeby otwierać nowe okno -- np. wiadomość. do pierwszego powinny być wysyłane informacje dotyczące stanu połączenia itd, itd, do aktualnego wszystko to, co jest związane z komendami wywoływanymi przez użytkownika. ui_beep() dźwięk. niestety to, jak go wytworzyć zależy od interfejsu. przy użyciu ncurses zwykłe putchar('\a') nie zadziała. ui_event(const char *event, ...) interfejs użytkownika może obsługiwać pewne zdarzenia: - "command" (char *cmd, ...) użytkownik wykonał komendę, aktualnie obsługiwana to "query". - "my_status" (char *status, char *reason) użytkownik zmienił stan na "away", "back", "invisible", "private_on", "private_off". - "my_status_raw" (int status, char *reason) użytkownik zmienił stan, podawany w liczbach rozumianych przez protokół. - "connecting" () klient próbuje się łączyć. - "connected" () klient połączył się. - "disconnected" () klient rozłączył się lub został rozłączony. ui_loop() główna pętla interfejsu, wywoływana zaraz po włączeniu klienta. powinna wywołać ekg_wait_for_key() przed wywołaniem funkcji czytającej z klawiatury, by w przerwach móc obsługiwać połączenia sieciowe. gdy użytkownik wyda jakąś komendę, powinna wywołać command_exec(). $Id$ ekg-1.9~pre+r2855/docs/vars.txt000066400000000000000000000750501174410337000162720ustar00rootroot00000000000000// mały opis dostępnych zmiennych // (c) copyright 2001-2006 wojtek kaniewski // adam wysocki uin typ: liczba domyślna wartość: brak określa numer GG, z którego ma korzystać klient. niezbędna do połączenia z serwerem. automatycznie ustawiana po udanej rejestracji, gdy wcześniej była pusta. password typ: tekst domyślna wartość: brak hasło użytkownika. niezbędne do połączenia z serwerem. automatycznie ustawiane po udanej rejestracji, gdy wcześniej było puste. email typ: tekst domyślna wartość: brak adres e-mail użytkownika. automatycznie ustawiany po udanej rejestracji, gdy wcześniej był pusty. audio_device typ: tekst domyślna wartość: "/dev/dsp" urządzenie dźwiękowe, którego należy używać przy rozmowach głosowych. jeśli poprzedzi się je minusem ,,-'', sygnał z wejścia urządzenia nie będzie wysyłany podczas rozmowy głosowej. auto_away typ: liczba domyślna wartość: 600 wartość określająca, po jakim czasie stan użytkownika zostanie zmieniony na ,,zajęty''. podaje się w sekundach. jeśli równa 0, nie będzie automatycznej zmiany. auto_away_keep_descr typ: bool domyślna wartość: 1 określa, czy zachowywać opis przy automatycznym przejściu w stan ,,zajęty'' niezależnie od wartości zmiennej ,,keep_reason''. auto_back typ: liczba domyślna wartość: 0 wartość określająca, czy stan ma być automatycznie zmieniany na dostępny, jeśli obecny stan ,,zajęty'' został ustawiony automatycznie. jeśli równa 1, stan jest zmieniany na dostępny przy wysłaniu jakiejkolwiek wiadomości. jeśli równa 2, przy wciśnięciu klawisza. auto_conference typ: bool domyślna wartość: 1 określa, czy w momencie wysyłania wiadomości za pomocą /chat lub /query do wielu użytkowników ma być automatycznie utworzona konferencja. auto_find typ: bool domyślna wartość: 0 określa, czy osoby, których nie mamy na liście kontaktów, a wysłały do nas wiadomość, mają być automatycznie wyszukane w katalogu. auto_reconnect typ: liczba domyślna wartość: 10 w przypadku nieudanego połączenia, określa po ilu sekundach program ma ponowić próbę. jeśli równa 0, nie próbuje więcej. auto_save typ: liczba domyślna wartość: 0 po jakim czasie automatycznie zapisać ustawienia, w sekundach. jeśli 0, nie zapisuje automatycznie. aspell typ: bool domyślna wartość: 0 określa, czy słownik ma zostać włączony. więcej o samym słowniku w slownik.txt. aspell_lang typ: tekst domyślna wartość: "pl" określa język wykorzystywany przez słownik. aspell_encoding typ: tekst domyślna wartość: "iso8859-2" określa kodowanie używane przez słownik. away_reason typ: tekst domyślna wartość: brak domyślny opis stanu zajętego, ustawiany przy zmianie bez podania parametru. back_reason typ: tekst domyślna wartość: brak domyślny opis stanu dostępnego, ustawiany przy zmianie bez podania parametru. backlog_overlap typ: liczba domyślna wartość: 0 ilość zachodzących na siebie podczas przewijania (Page Up, Page Down) linii. musi być mniejsza od rozmiaru okienka, w przeciwnym wypadku wartość zostanie zignorowana. działa tylko w interfejsie ncurses. backlog_size typ: liczba domyślna wartość: 1000 ilość linii, która będzie zapisywana w buforze ekranu (tym, który jest przewijany klawiszami Page Up i Page Down). nie może być mniejsza niż ilość linii na ekranie. działa tylko w interfejsie ncurses. beep typ: bool domyślna wartość: 1 określa, czy klient ma beepać w różnych sytuacjach. wyłączenie tej opcji spowoduje, że żadne zdarzenia związane z GG nie będą podnosiły alarmu. niestety nie obejmuje to zdarzeń związanych z wprowadzanym tekstem i przy tab-completion może się to przytrafić. beep_msg typ: bool domyślna wartość: 1 czy beepać przy nadchodzących wiadomościach. wyłączenie ,,beep'' wyłącza również tę opcję. beep_chat typ: bool domyślna wartość: 1 czy beepać przy rozmowach. wyłączenie ,,beep'' wyłącza również tę opcję. beep_notify typ: bool domyślna wartość: 1 czy beepać przy zmianie stanu któregoś ze znajomych. wyłączenie ,,beep'' wyłącza również tę opcję. beep_mail typ: bool domyślna wartość: 1 czy beepać przy nadejściu nowej poczty. wyłączenie ,,beep'' wyłącza również tę opcję. beep_title typ: liczba domyślna wartość: 0 czy informację o beepaniu umieścić również w pasku tytułowym? działa tylko w interfejsie ncurses na terminalu xterm. wartość 1 włącza informowanie w pasku, wartość 2 włącza informowanie w pasku i wyłącza zwykły sygnał dźwiękowy. check_mail typ: liczba domyślna wartość: 0 określa, czy ekg ma sprawdzać, czy nadeszła nowa poczta i informować o tym na pasku stanu. wartość 1 odpowiada sprawdzaniu skrzynki typu mbox, a wartość 2 skrzynki typu Maildir. dodanie wartości 4 oznacza, że oprócz informowania na pasku stanu, będziemy otrzymywać krótką informację o nadejściu poczty w aktualnym oknie. wszystkie dostępne wartości to: 0, 1, 2, 5, 6. check_mail_frequency typ: liczba domyślna wartość: 15 określa w sekundach, jak często sprawdzać, czy nie ma nowej poczty. check_mail_folders typ: tekst domyślna wartość: brak zawiera pliki (mbox) lub katalogi (Maildir) rozdzielone przecinkiem lub spacją, które ekg ma sprawdzać, poza główną skrzynką pocztową. może to być ścieżka bezwzględna lub względem katalogu domowego. główna w przypadku mbox to ta zapisana w zmiennej systemowej MAIL lub /var/mail/user przy braku tej zmiennej. dla Maildir z kolei, to katalog Maildir w katalogu domowym użytkownika. completion_notify typ: liczba domyślna wartość: 1 określa, czy po pojawieniu się któregoś ze znajomych jego nick ma być dopisywany do listy dopełniania klawiszem Tab. jeśli jest równa 2, jest również usuwany po przejściu w stan niedostępny. dodanie wartości 4 spowoduje, że dopisywani będą także ci, którzy pojawią się na liście ze stanem ,,zajęty''. dodanie wartości 8 spowoduje dopisywanie także tych, którzy mają stan ,,niewidoczny''. wszystkie dostępne wartości to: 0, 1, 2, 5, 6, 9, 10, 13, 14. ctrld_quits typ: bool domyślna wartość: 1 określa, czy wciśnięcie Ctrl-D w ostatnim okienku, nie będąc w trybie, rozmowy klient na zakończyć działanie. ma znaczenie tylko dla interfejsu readline. contacts typ: liczba domyślna wartość: 2 określa, czy okienko z listą obecnych ma być wyświetlone z prawej strony ekranu, jeśli jest równe 1. jeśli jest równe 2, informacje o zmianie stanu nie są wyświetlane, ignorując wartość zmiennej ,,display_notify''. działa tylko w interfejsie ncurses. contacts_groups typ: tekst domyślna wartość: brak oddzielone przecinkiem grupy, które można przełączać w liście kontaktów klawiszem F4. domyślnie wyświetlani są wszyscy użytkownicy. contacts_options typ: tekst domyślna wartość: brak opcje listy kontaktów oddzielone przecinkiem lub spacją. domyślne ustawienia to ,,right, frame, margin=1, nowrap, nodescr, order=501623''. możliwe stany to: 0 - dostępni, 1 - zajęci, 2 - niewidoczni, 3 - blokujący, 4 - niedostępni, 5 - poGGadaj ze mną, 6 - nie przeszkadzać. można pominąć niektóre stany -- nie będą po prostu wyświetlane na liście. lista dostępnych opcji: - left, right, top, bottom - położenie listy kontaktów na ekranie, - frame, noframe - lista oddzielona ramką od głównego okna lub nie, - framecolor=n - kolor ramki oddzielającej od głównego okna - margin=n, nomargin - margines między listą a głównym oknem lub brak, - wrap, nowrap - treść listy będzie zawijana lub ucinana, - descr, nodescr - opisy stanu będą lub nie będą wyświetlane, - order=n - kolejność wyświetlanych stanów. contacts_size typ: liczba domyślna wartość: 8 określa szerokość okienka z listą kontaktów. datestamp typ: tekst domyślna wartość: "%Y-%m-%d" w interfejsie ncurses określa format daty wyświetlanej, jeśli jest włączona opcja display_daychanges i od ostatniej aktywności w oknie zmienił się dzień. dokładny opis formatu zawiera strona manuala strftime(3). dcc typ: bool domyślna wartość: 0 włącza lub wyłącza bezpośrednie połączenia między klientami. zmiana tej opcji wymaga ponownego połączenia z serwerem, by przesłać nowy adres IP lub jego brak. dcc_ip typ: tekst domyślna wartość: brak określa adres IP, który jest wysyłany serwerowi. jeśli przypisze się tej zmiennej wartość ,,auto'', adres będzie ustalany automatycznie. jeśli chcemy bezproblemowo łączyć się z klientami z tej samej sieci LAN, dobrze jest podać adres IP sieci LAN zamiast zewnętrznego. dcc_backups typ: bool domyślna wartość: 0 włącza lub wyłącza zapisywanie nowych plików pod nowymi nazwami w przypadku, jeśli plik o podanej nazwie już istnieje. nowe nazwy są tworzone przez dodanie do nazwy pliku sufiksu .1, .2 itp. aż do .1000. dcc_dir typ: tekst domyślna wartość: brak określa katalog, do którego będą zapisywane pobierane pliki. dcc_filter typ: bool domyślna wartość: 1 określa czy klient będzie filtrował połączenia bezpośrednie z adresów innych niż w liście kontaktów. zmienna ta może być przydatna, gdy osoba, która chce nam przesłać plik znajduje się za źle skonfigurowanym firewallem, nie potrafi ustawić przekierowania portów lub podobnych sytuacjach. należy wtedy chwilowo ją wyłączyć. dcc_limit typ: tekst domyślna wartość: 30/30 określa limit bezpośrednich połączeń w danym przedziale czasu. liczba przed ukośnikiem określa maksymalną ilość połączeń, a liczba po ukośniku ilość sekund. po przekroczeniu tego progu bezpośrednie połączenia zostają wyłączone, by zapobiec atakom polegającym na wyczerpaniu zasobów klienta. zwykle po ponownym włączeniu bezpośrednich połączeń należy połączyć się ponownie z serwerem. dcc_port typ: liczba domyślna wartość: 1550 port, na którym ekg będzie oczekiwać na połączenia bezpośrednie. display_ack typ: liczba domyślna wartość: 3 określa, czy i które powiadomienia o wysłaniu wiadomości mają być wyświetlane. 0 - żadne, 1 - wszystkie, 2 - tylko kiedy wiadomość dotarła do adresata, 3 - tylko kiedy adresat jest niedostępny i wiadomość została zachowania na serwerze. display_color typ: liczba domyślna wartość: 1 wartość 0 wyłącza wyświetlanie kolorów, wartość 1 włącza. wartość 2 ma znaczenie tylko w interfejsie ncurses i powoduje wyświetlanie kolorów wszędzie poza paskiem stanu i nagłówkiem okna. display_color_map typ: tekst domyślna wartość: "nTgGbBrR" określa, jakie kolory będą przypisane różnym atrybutom tekstu. musi zawierać 8 znaków zgodnych ze spisem z pliku docs/themes.txt. każdy z nich określa kolejno kolor dla: - brak atrybutów, - pogrubiony, - pochyły, - pochyły+pogrubiony, - podkreślony, - podkreślony+pogrubiony, - podkreślony+pochyły, - podkreślony+pochyły+pogrubiony. display_crap typ: bool domyślna wartość: 1 mówi, czy w oknie rozmowy mają być wyświetlane komunikaty niezwiązane z rozmówcą. jeśli jest równe 0, w oknie rozmowy są wyświetlane tylko wiadomości i informacje o zmianie stanu rozmówcy. ma znaczenie tylko w interfejsie ncurses. display_daychanges typ: bool domyślna wartość: 1 określa, czy w interfejsie ncurses będą wyświetlane zmiany daty. zmiana jest wyświetlana tylko wtedy, kiedy w oknie nastąpi jakaś aktywność. zobacz też opis zmiennej datestamp. display_notify typ: liczba domyślna wartość: 1 wartość 0 powoduje ignorowanie zmian stanu znajomych, wartość 1 powoduje wyświetlanie wszystkich zmian, wartość 2 wyświetla tylko zmiany z niedostępnego na dostępny i na odwrót. dodanie 4 sprawia, że podczas wyświetlania brane są pod uwagę także osoby z włączonym trybem ,,tylko dla znajomych'', które mają nas na liście kontaktów, a my ich nie mamy. w interfejsie ncurses większy priorytet ma zmienna ,,contacts'', która przy wartości 2 ukrywa zmiany stanu. wszystkie dostępne wartości to 0, 1, 2, 5, 6. display_pl_chars typ: bool domyślna wartość: 1 jeśli włączone, wyświetlane są polskie literki na terminalu. w przeciwnym wypadku, zamieniane są na odpowiadające im literki ASCII. display_sent typ: bool domyślna wartość: 1 jeśli włączone, wyświetlane są również wysyłane wiadomości. należy zwrócić uwagę, że przy make_window = 2, wysłanie wiadomości utworzy automatycznie okienko rozmowy, a przy make_window = 1 tylko wtedy, gdy nie będzie żadnych wolnych okienek. display_welcome typ: bool domyślna wartość: 1 mówi, czy ekg ma wyświetlić tekst powitalny po uruchomieniu. display_token typ: bool domyślna wartość: 1 zmienna dostępna tylko gdy w systemie jest biblioteka pozwalająca dekodować pliki GIF. wyłączenie jej spowoduje działanie ekg tak, jakby biblioteki nie było, tj. zapisywanie tokenów do pliku. display_transparent typ: bool domyślna wartość: 1 mówi, czy w interfejsie ncurses tło ma być przezroczyste. zmiany odniosą skutek po ponownym uruchomieniu. dnd_reason typ: tekst domyślna wartość: brak domyślny opis stanu nie przeszkadzać, ustawiany przy zmianie bez podania parametru. emoticons typ: bool domyślna wartość: 1 uruchamia rozwijanie emotikonów w zdefiniowane teksty. więcej szczegółów w pliku docs/files.txt w sekcji 5-tej. encryption typ: liczba domyślna wartość: 0 włącza szyfrowanie wiadomości. jeśli w systemie jest zainstalowana biblioteka OpenSSL, możliwe jest używanie szyfrowania zgodnego z SIM opisanym na stronie http://gg.wha.la/crypt/. wartość 0 wyłącza szyfrowanie. wartość 1 włącza. ustawienie wartości 2 sprawia, że wysyłane są wiadomości niezaszyfrowane, ale odbierane szyfrowane są deszyfrowane. ustawienie 3 sprawia, że wiadomości odbierane nie są deszyfrowane, za to są szyfrowane wysyłane. enter_scrolls typ: bool domyślna wartość: 0 jeśli włączone, wciśnięcie klawisza Enter w pustej linii spowoduje przesunięcie ekranu o jedną linię. ma znaczenie tylko w interfejsie ncurses. events_delay typ: liczba domyślna wartość: 3 określa, po ilu sekundach od połączenia z serwerem zaczną działać zdarzenia ,,on'', dźwięki związane ze zmianami stanu i będą wyświetlane informacje o niedostępności osób. Chodzi o to, aby nie traktować początkowych informacji o stanie osób po połączeniu jako zmianę ich stanu. ffc_reason typ: tekst domyślna wartość: brak domyślny opis stanu poGGadaj ze mną, ustawiany przy zmianie bez podania parametru. files_mode_config typ: int domyślna wartość: 600 określa tryby dostępu do plików konfiguracyjnych ekg (config, userlist, debug, history, kolejka wiadomości, pliki wymieniane z ekgwap). wartość nie wpływa na tryby plików tworzonych podczas generowania crashdumpów oraz na tryby katalogów tworzonych podczas używania ekg. UWAGA: nieprawidłowe użycie tej zmiennej może umożliwić dostęp do konfiguracji (w tym hasła) oraz archiwum osobom niepowołanym. przed użyciem przeczytaj man chmod. files_mode_received typ: int domyślna wartość: 600 określa tryby dostępu do plików tworzonych przez ekg podczas odbierania danych od innych użytkowników (dcc oraz obrazki). domyślna wartość 600 oznacza, że pliki są dostępne jedynie dla użytkownika, który uruchomił ekg. więcej na temat uprawnień: man chmod. header_size typ: liczba domyślna wartość: 0 określa rozmiar nagłówka okna wyświetlanego na górze ekranu. maksymalna ilość linii to 5. ignore_unknown_sender typ: bool domyślna wartość: 0 określa, czy będą ignorowane wiadomości od osób, których nie mamy na swojej liście kontaktów. ignore_empty_msg typ: bool domyślna wartość: 0 określa, czy będą ignorowane puste wiadomości, zawierające jedynie obrazek, co może mieć miejsce, jeśli ktoś sprawdza, czy jesteśmy niewidoczni. image_size typ: int domyślna wartość: 255 maksymalny rozmiar akceptowanych przez nas obrazków w KiB. maksymalnie 255. istotne jedynie po włączeniu ,,receive_images''. ioctld_enable typ: liczba domyślna wartość: 1 jeśli 1, odpalany jest lokalny daemon ioctld, który lokalnie mruga diodkami i piszczy speakerem, jeżeli 2, odpalany jest daemon tcp/ip na porcie ioctld_net_port, do którego przekazywane są akcje blink_leds i beeps_spk. dzięki temu, używając ioctld-client.c z ekg/contrib, można lokalnie blinkać i beepać mając odpalone ekg na zdalnym hoście. jeżeli zaś 0, ioctld nie jest uruchamiany wcale. ioctld_net_port typ: liczba domyślna wartość: 22004 port, na którym nasłuchiwać będzie daemon ioctld przy ioctld_enable równym 2. irssi_set_mode typ: bool domyślna wartość: 0 jeśli 1, to podczas wykonania komendy /set arg1 wyświetlane będą wszystkie ustawienia, które w swojej nazwie zawierają arg1 (domyślnie arg1 musi być równe tej nazwie). /set arg1 arg2, przypisujące zmiennej arg1 wartość arg2 pozostaje bez zmian. pomysł zaczerpnięty z irssi. keep_reason typ: liczba domyślna wartość: 0 jeśli włączona, komendy ,,away'', ,,back'', ,,invisible'', ,,quit'' i ,,disconnect'' bez podanego powodu przejmą aktualny opis. zostanie on wraz ze stanem zapisany bez wyraźnego wydawania komendy zapisu konfiguracji. wartość 2 powoduje zapisywanie opisu bez stanu. last typ: liczba domyślna wartość: 0 wskazuje, czy zapisywać ostatnie wiadomości do podręcznego bufora (,,last_size'' musi być większe od 0). dla 1, będzie zapisywać tylko last_size wszystkich wiadomości przychodzących, dla 2, last_size wiadomości od każdego usera. dostępna jest jeszcze logiczna wartość 4, która pozwala logować wiadomości wysłane. dostępne są w takim razie wartości 0, 1, 2, 5 i 6. last_size typ: liczba domyślna wartość: 0 wskazuje, ile ma być zapisywanych wiadomości dla komendy ,,last''. local_ip typ: tekst domyślna wartość: brak określa adres IP, z którego następują wszelkiego rodzaju połączenia, na przykład z serwerem GG. w przypadku błędnie wpisanej wartości, zostanie ona usunięta. log typ: liczba domyślna wartość: 0 określa, czy i w jaki sposób będą logowane wysyłane i otrzymywane wiadomości. dla 0, nie będą. dla 1, będą logowane w pliku, który określa zmienna ,,log_path'' lub ,,~/.gg/history'' w przypadku jej braku. dla 2, będą logowane w katalogu wskazanym przez zmienną ,,log_path'', a nazwa pliku będzie numerem rozmówcy. jeśli mamy wkompilowaną obsługę skompresowanych logów, dodanie wartości 4 wymusi kompresję logów. nie będzie ona działała, jeśli istnieje już nieskompresowany log. należy go wcześniej skompresować poleceniem gzip. wszystkie dostępne wartości to: 0, 1, 2, 5, 6. log_ignored typ: liczba domyślna wartość: 0 określa, czy logujemy ignorowane wiadomości oraz zmiany stanu. log_status typ: liczba domyślna wartość: 0 określa, czy będą logowane zmiany stanu ludzi z listy (zmienna ,,log'' musi być różna od 0). jeśli jest równa 2, zmiany bez opisu nie będą logowane. log_path typ: tekst domyślna wartość: brak ścieżka, gdzie będą zachowywane wysyłane i otrzymane wiadomości. log_timestamp typ: tekst domyślna wartość: brak określa format czasu zapisywanego w historii. w przypadku braku, zmiennej, zapisuje w postaci ilości sekund od 1 stycznia 1970r. UTC. dokładny opis formatu zawiera strona manuala strftime(3). make_window typ: liczba domyślna wartość: 2 określa, czy będą tworzone nowe okienka dla nowych rozmów. dla 1 będzie wykorzystane pierwsze wolne okno (na którym z nikim jeszcze się nie rozmawia), lub tworzone nowe w przypadku braku wolnych. dla 2 bezwarunkowo utworzone zostanie nowe okno. jeśli zostanie dodana wartość 4, to wiadomości wysyłane przez /msg będą widoczne w oknie stanu. mesg typ: liczba domyślna wartość: 2 ustala, czy zezwalamy na wysyłanie do nas komunikatów za pomocą write, talk lub wall. dla 0 nie wyrażamy na to zgody, dla 1 zezwalamy na pisanie na nasz terminal. w przypadku wartości 2 używane są ustawienia sprzed uruchomienia ekg. msg_as_chat typ: int domyślna wartość: 0 określa, czy wiadomości wysyłane przy pomocy polecenia /msg mają być przesyłane tak, jakby były wysyłane przy pomocy polecenia /chat. dla wartości 1 inne różnice między /msg a /chat (np. nie otwieranie nowego okna rozmowy) nie są zmieniane. wartość 2 oznacza traktowanie polecenia /msg jako /chat we wszystkich aspektach. zmienna została wprowadzona w celu zapewnienia kompatybilności z klientami IRC - obecnie praktycznie żaden klient nie wysyła wiadomości tak, jak robi to polecenie /msg, a niektórzy użytkownicy, przyzwyczajeni do polecenia /msg w klientach IRC, nie chcą zmieniać przyzwyczajeń. mouse typ: bool domyślna wartość: 0 ustala, czy ma być włączona obsługa myszy w ekg. działa tylko z interfejsem ncurses. zmiana wartości tej zmiennej może też (ale nie musi) zmieniać widoczność lub kształt kursora myszy. więcej informacji na temat obsługi myszy w ekg znajduje sie w pliku docs/mysz.txt oraz pod adresem . nick typ: tekst domyślna wartość: brak ustala nasz nick, wyświetlany przy wysyłanych przez nas wiadomościach w oknie rozmowy. w przypadku, kiedy mamy swój numerek zapisany na liście, będzie wyświetlana pozycja z listy. proxy typ: tekst domyślna wartość: brak adres i port serwera proxy, oddzielone dwukropkiem. jeśli nie podano portu, domyślnie jest przyjmowany 8080. jeśli serwer proxy wymaga autoryzacji, należy poprzedzić go nazwą użytkownika, dwukropkiem, hasłem i małpą (np. ,,jan:tajnehasło@serwer'') proxy_forwarding typ: tekst domyślna wartość: brak adres i port (oddzielone dwukropkiem) serwera pośredniczącego (routera, proxy lub czegoś innego) przekierowany na port 1550 naszego komputera. query_commands typ: bool domyślna wartość: 1 możliwość wydawania długich poleceń podczas rozmowy z użytkownikiem bez poprzedzania ich znakiem '/'. quit_reason typ: tekst domyślna wartość: brak domyślny opis stanu niewidocznego, ustawiany przy zmianie bez podania parametru oraz stanu niedostępnego, ustawiany przy wychodzeniu. random_reason typ: liczba domyślna wartość: 0 określa, czy przy zmianie stanu i połączeniu ma być losowany opis (z ~/.gg/quit.reasons dla komend ,,quit'', ,,disconnect'', ,,invisible'', ~/.gg/away.reasons dla ,,away'' i ~/.gg/back.reasons dla ,,back''). dla 0 nie jest losowany, dla 1 losowany jest opis dotyczący stanu zajęty, dla 2 niedostępny, dla 4 dostępny, dla 8 niewidoczny. wartości te można ze sobą dodawać, np. 11 będzie dotyczyć stanów niedostępny, zajęty oraz niewidoczny. jeżeli z jakichś przyczyn nie powiedzie się odczyt, opis będzie pobierany ze zmiennych ,,away_reason'' lub ,,quit_reason'', o ile nie są puste. reason_limit typ: bool domyślna wartość: 0 określa, czy opisy stanu muszą mieścić się w określonym przez protokół limicie. jeśli opcja jest aktywna i długość opisu przekracza tą długość, komendy /away, /back i /invisible nie zostaną wykonane. receive_images typ: bool domyślna wartość: 0 określa, czy chcemy otrzymywać obrazki. włączenie tej opcji przy wyłączonej opcji ,,ignore_empty_msg'' może ujawnić nas dla użytkowników sprawdzających, czy jesteśmy niewidoczni. otrzymywane obrazki będą zapisywane w katalogu określonym zmienną dcc_dir. regex_flags typ: int domyślna wartość: 0 mapa bitowa określająca flagi podczas przetwarzania wyrażeń regularnych w poleceniu /list --regexp. 1 oznacza używanie podstawowych wyrażeń, 2 uwzględnianie rozmiaru znaków. save_question typ: bool domyślna wartość: 1 określa, czy ma być zadawane pytanie o zapis zmienionej konfiguracji przy wyjściu z programu. save_password typ: bool domyślna wartość: 1 określa, czy hasło ma być zapisywane w pliku konfiguracyjnym. opcja ta może przydać się, gdy boimy się administratora przeglądającego pliki użytkowników. server typ: tekst domyślna wartość: brak adresy IP serwerów, z którym klient powinien próbować się połączyć, pomijając właściwą procedurę łączenia się. przydane podczas awarii głównego serwera. adresy należy oddzielać przecinkami, średnikami lub spacjami. po dwukropku można podać port serwera. jeśli adres i port serwera zostaną poprzedzone tekstem ,,tls:'', klient spróbuje wynegocjować bezpieczne połączenie TLS z serwerem. jeśli zmiennej przypisze się wartość ,,tls'', spyta główny serwer o adres serwera obsługującego połączenia TLS i spróbuje się z nim połączyć. server_save typ: bool domyślna wartość: 0 określa, czy ekg ma zapamiętywać serwer, z którym ostatnio udało się połączyć. w przypadku włączenia tej zmiennej, zmienna ,,server'' będzie automatycznie uaktualniana, a zawartość wpisana przez użytkownika zostanie usunięta. slash_messages typ: bool domyślna wartość: 1 określa, czy wiadomości zaczynające się od ,,/'' mają być traktowane w pewnych warunkach jak wiadomości. wyłączenie tej opcji sprawia, że wszystko, co zostanie wpisane w oknie rozmowy a zaczyna się od ,,/'' zostanie potraktowane jak komenda. sms_away typ: liczba domyślna wartość: 0 włączenie tej opcji powoduje wysyłanie otrzymanych wiadomości na telefon komórkowy podczas nieobecności (stan ,,zajęty''). wymaga zdefiniowania zmiennych ,,sms_number'' i ,,sms_send_app''. jeżeli wartością jest 1, to zmienna ,,sms_away_limit'' (jeśli różna od 0) dotyczyć będzie łącznej liczby wiadomości wysłanych na telefon komórkowy. wartość 2, z kolei, wskazuje na to, że limit dotyczy ilości wiadomości od każdej osoby. dodanie wartości 4, spowoduje, że funkcja będzie także aktywna, gdy jesteśmy niewidoczni. sms_away_limit typ: liczba domyślna wartość: 0 określa limit wiadomości, które mogą zostać wysłane na telefon komórkowy podczas naszej nieobecności. jeśli 0, to wiadomości nie są limitowane. sms_max_length typ: liczba domyślna wartość: 100 maksymalna długość przekazywanych wiadomości. powyżej tego limitu wiadomość zostanie ucięta. jeśli równa 0, nie ma limitu. sms_number typ: tekst domyślna wartość: brak numer telefonu komórkowego, na który mają być wysyłane wiadomości podczas nieobecności. sms_send_app typ: tekst domyślna wartość: brak pełna ścieżka do programu wysyłającego SMSy. program musi za pierwszy parametr przyjmować numer odbiorcy, za drugi parametr treść wiadomości. do tego celu nadaje się program Mikołaja Rydzewskiego ze strony http://ceti.pl/~miki/ sort_windows typ: bool domyślna wartość: 0 włączenie tej opcji spowoduje przesuwanie okien przy usunięciu któregoś ze środka i likwidowanie luk w numeracji. na przykład, gdy mamy okna 1,2,3, to po usunięciu drugiego otrzymamy 1,2 zamiast 1,3. sound_app typ: tekst domyślna wartość: brak pełna ścieżka do programu odtwarzającego pliki zdefiniowane w zmiennych ,,sound_{msg,chat,sysmsg}_file''. program musi brać za pierwszy (i jedyny) parametr nazwę pliku. wavplay i mpg123 doskonale się nadają. sound_msg_file typ: tekst domyślna wartość: brak plik dźwiękowy odtwarzany po otrzymaniu wiadomości. sound_chat_file typ: tekst domyślna wartość: brak plik dźwiękowy odtwarzany w czasie rozmowy. sound_notify_file typ: tekst domyślna wartość: brak plik dźwiękowy odtwarzany po zmianie stanu któregoś ze znajomych. sound_sysmsg_file typ: tekst domyślna wartość: brak plik dźwiękowy odtwarzany po otrzymaniu wiadomości systemowej. sound_mail_file typ: tekst domyślna wartość: brak plik dźwiękowy odtwarzany po otrzymaniu nowej wiadomości e-mail. speech_app typ: tekst domyślna wartość: brak aplikacja używana do odczytywania tekstów wyświetlanych na ekranie. jej ustawienie powoduje również zmianę motywu na taki, który jest łatwiejszy do wymówienia. status_window typ: liczba domyślna wartość: 0 określa okno, do którego kierowane są zmiany stanu innych osób. 0 - okno rozmowy z osobą, której dotyczy zmiana (lub okno stanu, jeśli nie ma otwartego okna rozmowy z tą osobą), 1 - bieżące okno, 2 - okno stanu. statusbar_size typ: liczba domyślna wartość: 1 określa rozmiar paska stanu w liniach w zakresie od 1 do 5. statusbar_fgcolor typ: liczba domyślna wartość: 7 określa kolor tekstu w pasku stanu. z reguły jest nadpisany przez themik, więc ta zmienna jest mało przydatna. statusbar_bgcolor typ: liczba domyślna wartość: 4 określa kolor tła pasku stanu. domyślnie niebieski. tab_command typ: tekst domyślna wartość: "chat" komenda, która będzie wstawiana w linii poleceń z kolejną dostępną (patrz zmienna ,,completion_notify'') osobą z listy kontaktów po wciśnięciu klawisza Tab. theme typ: tekst domyślna wartość: brak zawiera nazwę pliku określającego motyw. time_deviation typ: liczba domyślna wartość: 300 określa zakres rozbieżności czasu odbieranych względem czasu systemowego w sekundach, który jest traktowany jako chwila aktualna. ma to wpływ na wyświetlanie timestampów przy odbieranych wiadomościach. jeśli czas odebranej wiadomości mieści się w +/- podanego zakresu, timestamp nie jest wyświetlany. timestamp typ: tekst domyślna wartość: "%H:%M " w interfejsie ncurses określa format czasu wyświetlanego na początku każdej linii. dokładny opis formatu zawiera strona manuala strftime(3). userlist_backup typ: bool domyślna wartość: 0 określa, czy przed zaimportowaniem listy kontaktów z serwera zapisać aktualną listę w pliku ~/.gg/userlist.pid (gdzie pid to numer procesu ekg). jeżeli zaimportowana zostanie także konfiguracja, to aktualna konfiguracja zostanie zapisana w pliku ~/.gg/config.pid. wap_enabled typ: bool domyślna wartość: 2 jeśli wkompilowano obsługę WAP, pozawala tymczasowo wyłączyć tę usługę. wartość 1 używa poprzedniego formatu zapisu do pliku WAP. windows_save typ: liczba domyślna wartość: 0 określa, czy ustawienie okienek ma być zachowywane. jeśli wynosi 0, okienka nie są zachowywane. dla wartości 1 są zachowywane przy wychodzeniu z programu. ustawienie 2 powoduje zapis tylko przy użyciu polecenia /save wartość 3 natomiast sprawia, że ustawienie okienek jest zapisywane zarówno przy wychodzeniu z programu, jak przy /save. warto wspomnieć, że polecenie /reload nie przywraca stanu okienek. zmienna ma znaczenie tylko w interfejsie ncurses. status typ: liczba, zmienna wewnętrzna, ukryta określa stan klienta (zajęty/niewidoczny/tylko dla przyjaciół) po uruchomieniu i pierwszym połączeniu. zachowywana przy poleceniu ,,save''. reason typ: tekst, zmienna wewnętrzna, ukryta określa opis stanu klienta. zachowywana przy poleceniu ,,save''. jest usuwana przy każdej zmianie stanu lub wyjściu z klienta, chyba że włączona jest zmienna ,,keep_reason''. interface typ: tekst, zmienna wewnętrzna, ukryta określa domyślny interfejs programu. jej wartość jest zmieniana przez podanie parametru -f w wywołaniu programu i automatycznie zapisywana. password_cp1250 typ: bool, zmienna wewnętrzna, ukryta przy włączonej opcji nie będzie przeprowadzana konwersja hasła ze standardu ISO-8859-2 na CP1250. protocol typ: liczba, zmienna wewnętrzna, ukryta określa wersję klienta, którą przedstawia się ekg. może być używana do udawania nowszego klienta, gdy biblioteka jeszcze jej nie zna. zmienna ta nie powinna być używana przez zwykłych użytkowników. last_sysmsg typ: liczba, zmienna wewnętrzna, ukryta określa numer ostatniej wiadomości systemowej. windows_layout typ: tekst, zmienna wewnętrzna, ukryta zawiera informacje o okienkach. wpis każdego okna jest rozdzielony znakiem ,,|''. jeśli okno nie ma przypisanej rozmowy, wpis jest pusty. jeśli okno nie istnieje, wpis zawiera ,,-''. $Id$ ekg-1.9~pre+r2855/docs/voip.txt000066400000000000000000000012751174410337000162720ustar00rootroot00000000000000// rozmowy głosowe w ekg // (c) copyright 2002 wojtek kaniewski obowiązuje lektura pliku ,,dcc.txt'' lista wad: - działa tylko na Linuksie ze sterownikami OSS, - działa tylko z kartami dźwiękowymi obsługującymi full-duplex, częstotliwość próbkowania 8000Hz i 16-bitową rozdzielczość, - działa tylko jeśli jest zainstalowana biblioteka libgsm skompilowana z opcją -DWAV49 (w PLD wystarczy zainstalować pakiety libgsm oraz libgsm-devel), - wyświetla _duuuużo_ śmieci w oknie debugowania. by rozpocząć rozmowę należy wpisać: dcc voice by zakończyć: dcc close <#numer> gdzie <#numer> to numer połączenia wyświetlony przez polecenie ,,dcc show''. $Id$ ekg-1.9~pre+r2855/dumps/000077500000000000000000000000001174410337000147475ustar00rootroot00000000000000ekg-1.9~pre+r2855/dumps/gg/000077500000000000000000000000001174410337000153445ustar00rootroot00000000000000ekg-1.9~pre+r2855/dumps/gg/0.logout.txt000066400000000000000000000012461174410337000175570ustar00rootroot0000000000000020:28:40.673258 1.2.3.4.1031 > 195.117.45.130.8074: P 487845:487857(12) ack 662586188 win 8440 (DF) (ttl 127, id 47874) 45 00 00 34 bb 02 40 00 7f 06 4b 60 01 02 03 04 E..4ť.@...K`.... c3 75 2d 82 04 07 1f 8a 00 07 71 a5 27 7e 43 4c Ău-.......qĽ'~CL 50 18 20 f8 92 5f 00 00 02 00 00 00 04 00 00 00 P. ř._.......... 01 00 00 00 .... 20:28:40.703258 195.117.45.130.8074 > 1.2.3.4.1031: F 1:1(0) ack 12 win 16486 (DF) (ttl 118, id 23399) 20:28:40.833258 1.2.3.4.1031 > 195.117.45.130.8074: F 12:12(0) ack 2 win 8440 (DF) (ttl 127, id 48130) 20:28:40.873258 195.117.45.130.8074 > 1.2.3.4.1031: . ack 13 win 16486 (DF) (ttl 118, id 23499) ekg-1.9~pre+r2855/dumps/gg/0.plumk.txt000066400000000000000000000072031174410337000173750ustar00rootroot0000000000000020:20:37.993258 1.2.3.4.1030 > 195.117.45.131.http: S 487216:487216(0) win 8192 (DF) (ttl 127, id 1793) 20:20:38.033258 195.117.45.131.http > 1.2.3.4.1030: S 2821328989:2821328989(0) ack 487217 win 16616 (DF) (ttl 118, id 5863) 20:20:38.243258 1.2.3.4.1030 > 195.117.45.131.http: . ack 1 win 8576 (DF) (ttl 127, id 2049) 20:20:38.273258 1.2.3.4.1030 > 195.117.45.131.http: P 1:157(156) ack 1 win 8576 (DF) (ttl 127, id 2305) 45 00 00 c4 09 01 40 00 7f 06 fc d0 01 02 03 04 E..Ä..@...üĐ.... c3 75 2d 83 04 06 00 50 00 07 6f 31 a8 2a 10 5e Ău-....P..o1¨*.^ 50 18 21 80 1f a6 00 00 47 45 54 20 2f 61 70 70 P.!..Ś..GET /app 73 76 63 2f 61 70 ... svc/ap 20:20:38.323258 195.117.45.131.http > 1.2.3.4.1030: P 1:76(75) ack 157 win 16460 (DF) (ttl 118, id 5976) 45 00 00 73 17 58 40 00 76 06 f7 ca c3 75 2d 83 E..s.X@.v.÷ĘĂu-. 01 02 03 04 00 50 04 06 a8 2a 10 5e 00 07 6f cd .....P..¨*.^..oÍ 50 18 40 4c 67 d8 00 00 48 54 54 50 2f 31 2e 30 P.@LgŘ..HTTP/1.0 20 32 30 30 20 4f ... 200 O 20:20:38.323258 195.117.45.131.http > 1.2.3.4.1030: F 76:76(0) ack 157 win 16460 (DF) (ttl 118, id 5977) 20:20:38.503258 1.2.3.4.1030 > 195.117.45.131.http: . ack 77 win 8501 (DF) (ttl 127, id 3073) 20:20:38.513258 1.2.3.4.1030 > 195.117.45.131.http: F 157:157(0) ack 77 win 8501 (DF) (ttl 127, id 3329) 20:20:38.523258 1.2.3.4.1031 > 195.117.45.130.8074: S 487726:487726(0) win 8192 (DF) (ttl 127, id 3585) 20:20:38.543258 195.117.45.131.http > 1.2.3.4.1030: . ack 158 win 16460 (DF) (ttl 118, id 6058) 20:20:38.573258 195.117.45.130.8074 > 1.2.3.4.1031: S 662586051:662586051(0) ack 487727 win 16616 (DF) (ttl 118, id 45316) 20:20:38.723258 1.2.3.4.1031 > 195.117.45.130.8074: . ack 1 win 8576 (DF) (ttl 127, id 4097) 20:20:38.763258 195.117.45.130.8074 > 1.2.3.4.1031: P 1:13(12) ack 1 win 16616 (DF) (ttl 118, id 45479) 45 00 00 34 b1 a7 40 00 76 06 5d bb c3 75 2d 82 E..4ą§@.v.]ťĂu-. 01 02 03 04 1f 8a 04 07 27 7e 42 c4 00 07 71 2f ........'~BÄ..q/ 50 18 40 e8 77 06 00 00 01 00 00 00 04 00 00 00 P.@čw........... fe 66 00 00 ţf.. 20:20:38.903258 1.2.3.4.1031 > 195.117.45.130.8074: P 1:31(30) ack 13 win 8564 (DF) (ttl 127, id 4609) 45 00 00 46 12 01 40 00 7f 06 f4 4f 01 02 03 04 E..F..@...ôO.... c3 75 2d 82 04 07 1f 8a 00 07 71 2f 27 7e 42 d0 Ău-.......q/'~BĐ 50 18 21 74 4a 14 00 00 0c 00 00 00 16 00 00 00 P.!tJ........... 25 2b 08 00 c0 39 ... %+..Ŕ9 20:20:38.963258 195.117.45.130.8074 > 1.2.3.4.1031: P 13:21(8) ack 31 win 16586 (DF) (ttl 118, id 45619) 45 00 00 30 b2 33 40 00 76 06 5d 33 c3 75 2d 82 E..0˛3@.v.]3Ău-. 01 02 03 04 1f 8a 04 07 27 7e 42 d0 00 07 71 4d ........'~BĐ..qM 50 18 40 ca 77 65 00 00 03 00 00 00 00 00 00 00 P.@Ęwe.......... 20:20:39.123258 1.2.3.4.1031 > 195.117.45.130.8074: P 31:59(28) ack 21 win 8556 (DF) (ttl 127, id 5121) 45 00 00 44 14 01 40 00 7f 06 f2 51 01 02 03 04 E..D..@...ňQ.... c3 75 2d 82 04 07 1f 8a 00 07 71 4d 27 7e 42 d8 Ău-.......qM'~BŘ 50 18 21 6c cd 25 00 00 10 00 00 00 14 00 00 00 P.!lÍ%.......... f7 1a 07 00 03 5f ... ÷...._ 20:20:39.173258 195.117.45.130.8074 > 1.2.3.4.1031: P 21:49(28) ack 59 win 16558 (DF) (ttl 118, id 45790) 45 00 00 44 b2 de 40 00 76 06 5c 74 c3 75 2d 82 E..D˛Ţ@.v.\tĂu-. 01 02 03 04 1f 8a 04 07 27 7e 42 d8 00 07 71 69 ........'~BŘ..qi 50 18 40 ae 69 82 00 00 0c 00 00 00 14 00 00 00 P.@Ži........... d3 c0 00 00 02 00 ÓŔ.... 20:20:39.513258 1.2.3.4.1031 > 195.117.45.130.8074: . ack 49 win 8528 (DF) (ttl 127, id 5889) ekg-1.9~pre+r2855/dumps/gg/1.conn.txt000066400000000000000000000026611174410337000172060ustar00rootroot0000000000000011:01:44.518787 217.17.33.21.8074 > 1.2.3.4.1032: P 3989893356:3989893368(12) ack 278789 win 16616 (DF) 45 00 00 34 b0 6e 40 00 75 06 56 c5 d9 11 21 15 E..4°n@.u.VĹŮ.!. 01 02 03 04 1f 8a 04 08 ed d0 f0 ec 00 04 41 05 ........íĐđě..A. 50 18 40 e8 1a c9 00 00 01 00 00 00 04 00 00 00 P.@č.É.......... 0d 26 00 00 .&.. 11:01:44.648787 1.2.3.4.1032 > 217.17.33.21.8074: P 1:31(30) ack 12 win 8564 (DF) 45 00 00 46 09 02 40 00 7f 06 f4 1f 01 02 03 04 E..F..@...ô..... d9 11 21 15 04 08 1f 8a 00 04 41 05 ed d0 f0 f8 Ů.!.......A.íĐđř 50 18 21 74 94 07 00 00 0c 00 00 00 16 00 00 00 P.!t............ 25 2b 08 00 a0 78 a9 29 02 00 00 00 0b 00 00 00 %+...xŠ)........ 01 02 03 04 0e 06 ...... 11:01:44.688787 217.17.33.21.8074 > 1.2.3.4.1032: P 12:20(8) ack 31 win 16586 (DF) 45 00 00 30 b0 e6 40 00 75 06 56 51 d9 11 21 15 E..0°ć@.u.VQŮ.!. 01 02 03 04 1f 8a 04 08 ed d0 f0 f8 00 04 41 23 ........íĐđř..A# 50 18 40 ca 29 e7 00 00 03 00 00 00 00 00 00 00 P.@Ę)ç.......... 11:01:44.798787 1.2.3.4.1032 > 217.17.33.21.8074: P 31:59(28) ack 20 win 8556 (DF) 45 00 00 44 0a 02 40 00 7f 06 f3 21 01 02 03 04 E..D..@...ó!.... d9 11 21 15 04 08 1f 8a 00 04 41 23 ed d0 f1 00 Ů.!.......A#íĐń. 50 18 21 6c 7f a7 00 00 10 00 00 00 14 00 00 00 P.!l.§.......... f7 1a 07 00 03 5f 18 07 00 03 d3 c0 00 00 03 39 ÷...._....ÓŔ...9 b8 00 00 03 ¸... ekg-1.9~pre+r2855/dumps/gg/1.disconn.txt000066400000000000000000000005431174410337000177030ustar00rootroot0000000000000011:03:53.138787 1.2.3.4.1032 > 217.17.33.21.8074: P 278895:278907(12) ack 3989893412 win 8520 (DF) 45 00 00 34 2c 03 40 00 7f 06 d1 30 01 02 03 04 E..4,.@...Ń0.... d9 11 21 15 04 08 1f 8a 00 04 41 6f ed d0 f1 24 Ů.!.......AoíĐń$ 50 18 21 48 44 ed 00 00 02 00 00 00 04 00 00 00 P.!HDí.......... 01 00 00 00 .... ekg-1.9~pre+r2855/dumps/gg/1.recv.txt000066400000000000000000000031441174410337000172050ustar00rootroot0000000000000011:07:53.218787 195.117.101.166.1059 > 1.2.3.4.1550: P 160205257:160205261(4) ack 647643 win 8192 (DF) 45 00 00 2c 00 f9 40 00 1b 06 31 4e c3 75 65 a6 E..,.ů@...1NĂueŚ 01 02 03 04 04 23 06 0e 09 8c 89 c9 00 09 e1 db .....#.....É..áŰ 50 18 20 00 a9 2c 00 00 38 ab 01 00 00 00 P. .Š,..8Ť.... 11:07:53.718787 195.117.101.166.1059 > 1.2.3.4.1550: P 4:8(4) ack 1 win 8192 (DF) 45 00 00 2c 00 fa 40 00 1b 06 31 4d c3 75 65 a6 E..,.ú@...1MĂueŚ 01 02 03 04 04 23 06 0e 09 8c 89 cd 00 09 e1 db .....#.....Í..áŰ 50 18 20 00 b5 a8 00 00 25 2b 08 00 00 00 P. .ľ¨..%+.... 11:07:53.818787 1.2.3.4.1550 > 195.117.101.166.1059: P 1:5(4) ack 8 win 8568 (DF) 45 00 00 2c 8c 05 40 00 7f 06 42 41 01 02 03 04 E..,..@...BA.... c3 75 65 a6 06 0e 04 23 00 09 e1 db 09 8c 89 d1 ĂueŚ...#..áŰ...Ń 50 18 21 78 4a cc 00 00 55 44 41 47 P.!xJĚ..UDAG 11:07:53.958787 195.117.101.166.1059 > 1.2.3.4.1550: P 8:12(4) ack 5 win 8188 (DF) 45 00 00 2c 00 fb 40 00 1b 06 31 4c c3 75 65 a6 E..,.ű@...1LĂueŚ 01 02 03 04 04 23 06 0e 09 8c 89 d1 00 09 e1 df .....#.....Ń..áß 50 18 1f fc e1 cf 00 00 01 00 00 00 00 00 P..üáĎ........ 11:07:54.878787 217.17.33.21.8074 > 1.2.3.4.1041: P 1680968211:1680968253(42) ack 537449 win 16553 (DF) 45 00 00 52 ec c5 40 00 75 06 1a 50 d9 11 21 15 E..RěĹ@.u..PŮ.!. 01 02 03 04 1f 8a 04 11 64 31 8a 13 00 08 33 69 ........d1....3i 50 18 40 a9 09 01 00 00 0a 00 00 00 22 00 00 00 P.@Š........"... 38 ab 01 00 10 10 74 01 78 4d 8e 3a 08 00 00 00 8Ť....t.xM.:.... 41 41 41 41 41 41 41 41 41 41 41 41 41 41 20 3b AAAAAAAAAAAAAA ; 5d 00 ]. ekg-1.9~pre+r2855/dumps/gg/1.send2.txt000066400000000000000000000014101174410337000172530ustar00rootroot0000000000000011:03:34.698787 1.2.3.4.1032 > 217.17.33.21.8074: P 278860:278895(35) ack 3989893392 win 8540 (DF) 45 00 00 4b fd 02 40 00 7f 06 00 1a 01 02 03 04 E..Ký.@......... d9 11 21 15 04 08 1f 8a 00 04 41 4c ed d0 f1 10 Ů.!.......ALíĐń. 50 18 21 5c 33 90 00 00 0b 00 00 00 1b 00 00 00 P.!\3........... 38 ab 01 00 a0 19 74 01 04 00 00 00 64 75 70 61 8Ť....t.....dupa 20 64 75 70 61 20 64 75 70 61 00 dupa dupa. 11:03:35.008787 217.17.33.21.8074 > 1.2.3.4.1032: P 1:21(20) ack 35 win 16510 (DF) 45 00 00 3c fa 4d 40 00 75 06 0c de d9 11 21 15 E..<úM@.u..ŢŮ.!. 01 02 03 04 1f 8a 04 08 ed d0 f1 10 00 04 41 6f ........íĐń...Ao 50 18 40 7e cb fc 00 00 05 00 00 00 0c 00 00 00 P.@~Ëü.......... 02 00 00 00 38 ab 01 00 a0 19 74 01 ....8Ť....t. ekg-1.9~pre+r2855/dumps/gg/2.send.txt000066400000000000000000000030101174410337000171700ustar00rootroot0000000000000012:55:16.658787 1.2.3.4.1028 > 217.17.33.21.8074: P 397496:397535(39) ack 3641993108 win 8548 (DF) 45 00 00 4f ff 04 40 00 7f 06 fe 13 01 02 03 04 E..O˙.@...ţ..... d9 11 21 15 04 04 1f 8a 00 06 10 b8 d9 14 67 94 Ů.!........¸Ů.g. 50 18 21 64 20 dc 00 00 0b 00 00 00 1f 00 00 00 P.!d Ü.......... 38 ab 01 00 30 17 74 01 04 00 00 00 64 75 70 61 8Ť..0.t.....dupa 20 64 75 70 61 20 64 75 70 61 20 3b 2d 3e 00 dupa dupa ;->. 12:55:16.718787 217.17.33.21.8074 > 1.2.3.4.1028: P 1:21(20) ack 39 win 16490 (DF) 45 00 00 3c 46 98 40 00 75 06 c0 93 d9 11 21 15 E.. 217.17.33.21.8074: P 39:77(38) ack 21 win 8528 (DF) 45 00 00 4e 15 05 40 00 7f 06 e8 14 01 02 03 04 E..N..@...č..... d9 11 21 15 04 04 1f 8a 00 06 10 df d9 14 67 a8 Ů.!........ßŮ.g¨ 50 18 21 50 af be 00 00 0b 00 00 00 1e 00 00 00 P.!PŻž.......... f7 1a 07 00 40 23 74 01 04 00 00 00 74 65 73 74 ÷...@#t.....test 75 6a 65 20 74 79 6c 6b 6f 20 3b 2d 3e 00 uje tylko ;->. 12:55:31.978787 217.17.33.21.8074 > 1.2.3.4.1028: P 21:41(20) ack 77 win 16452 (DF) 45 00 00 3c 6e fb 40 00 75 06 98 30 d9 11 21 15 E.. cos.gadu-gadu.pl.8074: P 397472:397484(12) ack 3641993100 win 8556 (DF) 4500 0034 d803 4000 7f06 2530 0102 0304 E..4..@...%0.... d911 2115 0404 1f8a 0006 10a0 d914 678c ..!...........g. 5018 216c 11ef 0000 0200 0000 0400 0000 P.!l............ 0300 0000 .... 12:51:01.898787 cos.gadu-gadu.pl.8074 > 1.2.3.4.1028: . ack 12 win 16541 (DF) 4500 0028 910c 4000 7506 7633 d911 2115 E..(..@.u.v3..!. 0102 0304 1f8a 0404 d914 678c 0006 10ac ..........g..... 5010 409d fbc5 0000 0000 0000 0000 P.@........... ekg-1.9~pre+r2855/dumps/gg/2.status2.txt000066400000000000000000000011041174410337000176460ustar00rootroot0000000000000012:51:13.728787 1.2.3.4.1028 > cos.gadu-gadu.pl.8074: P 397484:397496(12) ack 3641993100 win 8556 (DF) 4500 0034 e603 4000 7f06 1730 0102 0304 E..4..@....0.... d911 2115 0404 1f8a 0006 10ac d914 678c ..!...........g. 5018 216c 12e3 0000 0200 0000 0400 0000 P.!l............ 0200 0000 .... 12:51:13.928787 cos.gadu-gadu.pl.8074 > 1.2.3.4.1028: . ack 12 win 16529 (DF) 4500 0028 afa4 4000 7506 579b d911 2115 E..(..@.u.W...!. 0102 0304 1f8a 0404 d914 678c 0006 10b8 ..........g..... 5010 4091 fbc5 0000 0000 0000 0000 P.@........... ekg-1.9~pre+r2855/dumps/gg/6.add.txt000066400000000000000000000012731174410337000170040ustar00rootroot0000000000000017:00:19.453667 1.2.3.4.1073 > 217.17.33.21.8074: P 1836857:1836870(13) ack 1449087043 win 8540 (DF) 45 00 00 35 98 0c 40 00 7f 06 65 26 01 02 03 04 E..5..@...e&.... d9 11 21 15 04 31 1f 8a 00 1c 07 39 56 5f 50 43 Ů.!..1.....9V_PC 50 18 21 5c 18 c0 00 00 0d 00 00 00 05 00 00 00 P.!\.Ŕ.......... 88 60 08 00 03 .`... 17:00:19.493667 217.17.33.21.8074 > 1.2.3.4.1073: P 1:29(28) ack 13 win 16524 (DF) 45 00 00 44 eb 77 40 00 75 06 1b ac d9 11 21 15 E..Dëw@.u..ŹŮ.!. 01 02 03 04 1f 8a 04 31 56 5f 50 43 00 1c 07 46 .......1V_PC...F 50 18 40 8c d1 6d 00 00 0c 00 00 00 14 00 00 00 P.@.Ńm.......... 88 60 08 00 02 00 .`.... ekg-1.9~pre+r2855/dumps/gg/6.conn-notify.txt000066400000000000000000000017751174410337000205260ustar00rootroot0000000000000017:05:22.873667 1.2.3.4.1084 > 217.17.33.21.8074: P 31:74(43) ack 20 win 8556 (DF) 45 00 00 53 27 0e 40 00 7f 06 d6 06 01 02 03 04 E..S'.@...Ö..... d9 11 21 15 04 3c 1f 8a 00 29 b0 3c 96 4d 51 c5 Ů.!..<...)°<.MQĹ 50 18 21 6c fa 76 00 00 10 00 00 00 23 00 00 00 P.!lúv......#... f7 1a 07 00 03 5f 18 07 00 03 d3 c0 00 00 03 39 ÷...._....ÓŔ...9 b8 00 00 03 38 ab 01 00 03 88 60 08 00 03 55 2f ¸...8Ť....`...U/ 08 00 03 ... 17:05:22.933667 217.17.33.21.8074 > 1.2.3.4.1084: P 20:88(68) ack 74 win 16543 (DF) 45 00 00 6c fb 53 40 00 75 06 0b a8 d9 11 21 15 E..lűS@.u..¨Ů.!. 01 02 03 04 1f 8a 04 3c 96 4d 51 c5 00 29 b0 67 .......<.MQĹ.)°g 50 18 40 9f e1 d3 00 00 0c 00 00 00 3c 00 00 00 P.@.áÓ......<... f7 1a 07 00 02 00 00 00 d5 4c 66 0b 0e 06 0b 00 ÷.......ŐLf..... 00 00 0e 06 88 60 08 00 02 00 00 00 00 00 00 00 .....`.......... 02 00 0b 00 00 00 0e 06 55 2f 08 00 02 00 00 00 ........U/...... 00 00 00 00 02 00 0b 00 00 00 0e 06 ............ ekg-1.9~pre+r2855/dumps/gg/6.leave-join.txt000066400000000000000000000022221174410337000203000ustar00rootroot0000000000000017:07:16.383667 217.17.33.21.8074 > 1.2.3.4.1084: P 167:183(16) ack 74 win 16543 (DF) 45 00 00 38 1c df 40 00 75 06 ea 50 d9 11 21 15 E..8.ß@.u.ęPŮ.!. 01 02 03 04 1f 8a 04 3c 96 4d 52 58 00 29 b0 67 .......<.MRX.)°g 50 18 40 9f aa 75 00 00 02 00 00 00 08 00 00 00 P.@.Şu.......... f7 1a 07 00 01 00 00 00 ÷....... 17:07:23.353667 217.17.33.21.8074 > 1.2.3.4.1084: P 183:211(28) ack 74 win 16543 (DF) 45 00 00 44 2e 7d 40 00 75 06 d8 a6 d9 11 21 15 E..D.}@.u.ŘŚŮ.!. 01 02 03 04 1f 8a 04 3c 96 4d 52 68 00 29 b0 67 .......<.MRh.)°g 50 18 40 9f 30 f5 00 00 0c 00 00 00 14 00 00 00 P.@.0ő.......... f7 1a 07 00 02 00 00 00 d5 4c 66 0b 0e 06 0b 00 ÷.......ŐLf..... 00 00 0e 06 .... 17:07:29.513667 217.17.33.21.8074 > 1.2.3.4.1084: P 211:245(34) ack 74 win 16543 (DF) 45 00 00 4a 3d 69 40 00 75 06 c9 b4 d9 11 21 15 E..J=i@.u.É´Ů.!. 01 02 03 04 1f 8a 04 3c 96 4d 52 84 00 29 b0 67 .......<.MR..)°g 50 18 40 9f 22 ef 00 00 0a 00 00 00 1a 00 00 00 P.@."ď.......... f7 1a 07 00 50 4c 74 01 0d a2 8e 3a 08 00 00 00 ÷...PLt..˘.:.... 6d 6f bf 65 20 62 79 e6 3f 00 może być?. ekg-1.9~pre+r2855/dumps/gg/7.mesgi.txt000066400000000000000000000075121174410337000173630ustar00rootroot0000000000000022:34:31.910251 cos.gadu-gadu.pl.8074 > 10.0.0.3.1615: P 1074091855:1074091867(12) ack 7207174 win 17520 (DF) (ttl 115, id 29265) 45 00 00 34 72 51 40 00 73 06 91 49 d9 11 21 15 E..4rQ@.s..IŮ.!. 0a 00 00 03 1f 8a 06 4f 40 05 57 4f 00 6d f9 06 .......O@.WO.mů. 50 18 44 70 4e 5c 00 00 01 00 00 00 04 00 00 00 P.DpN\.......... 5d 29 00 00 ]).. 22:34:31.916416 10.0.0.3.1615 > cos.gadu-gadu.pl.8074: P 1:31(30) ack 12 win 8748 (DF) (ttl 32, id 51737) 45 00 00 46 ca 19 40 00 20 06 8c 6f 0a 00 00 03 E..FĘ.@. ..o.... d9 11 21 15 06 4f 1f 8a 00 6d f9 06 40 05 57 5b Ů.!..O...mů.@.W[ 50 18 22 2c 82 f6 00 00 0c 00 00 00 16 00 00 00 P.",.ö.......... 4a e6 0a 00 00 58 b3 6d 02 00 00 00 0b 00 00 00 Jć...Xłm........ 0a 00 00 03 0e 06 ...... 22:34:32.170210 cos.gadu-gadu.pl.8074 > 10.0.0.3.1615: P 12:20(8) ack 31 win 17490 (DF) (ttl 115, id 29475) 45 00 00 30 73 23 40 00 73 06 90 7b d9 11 21 15 E..0s#@.s..{Ů.!. 0a 00 00 03 1f 8a 06 4f 40 05 57 5b 00 6d f9 24 .......O@.W[.mů$ 50 18 44 52 ad 7d 00 00 03 00 00 00 00 00 00 00 P.DR­}.......... 22:34:32.203691 10.0.0.3.1615 > cos.gadu-gadu.pl.8074: P 31:49(18) ack 20 win 8740 (DF) (ttl 32, id 51993) 45 00 00 3a cb 19 40 00 20 06 8b 7b 0a 00 00 03 E..:Ë.@. ..{.... d9 11 21 15 06 4f 1f 8a 00 6d f9 24 40 05 57 63 Ů.!..O...mů$@.Wc 50 18 22 24 0a fb 00 00 10 00 00 00 0a 00 00 00 P."$.ű.......... 25 2b 08 00 03 66 7d 0a 00 03 %+...f}... 22:34:50.407921 10.0.0.3.1615 > cos.gadu-gadu.pl.8074: P 49:78(29) ack 20 win 8740 (DF) (ttl 32, id 61977) 45 00 00 45 f2 19 40 00 20 06 64 70 0a 00 00 03 E..Eň.@. .dp.... d9 11 21 15 06 4f 1f 8a 00 6d f9 36 40 05 57 63 Ů.!..O...mů6@.Wc 50 18 22 24 af 9e 00 00 0b 00 00 00 15 00 00 00 P."$Ż........... 25 2b 08 00 d0 1b 5d 01 04 00 00 00 64 67 76 65 %+..Đ.].....dgve 61 67 68 61 00 agha. 22:34:50.870175 cos.gadu-gadu.pl.8074 > 10.0.0.3.1615: P 20:40(20) ack 78 win 17443 (DF) (ttl 115, id 43802) 45 00 00 3c ab 1a 40 00 73 06 58 78 d9 11 21 15 E..<Ť.@.s.XxŮ.!. 0a 00 00 03 1f 8a 06 4f 40 05 57 63 00 6d f9 53 .......O@.Wc.můS 50 18 44 23 43 21 00 00 05 00 00 00 0c 00 00 00 P.D#C!.......... 02 00 00 00 25 2b 08 00 d0 1b 5d 01 ....%+..Đ.]. 22:35:00.942051 10.0.0.3.1615 > cos.gadu-gadu.pl.8074: P 78:110(32) ack 40 win 8720 (DF) (ttl 32, id 2330) 45 00 00 48 09 1a 40 00 20 06 4d 6d 0a 00 00 03 E..H..@. .Mm.... d9 11 21 15 06 4f 1f 8a 00 6d f9 53 40 05 57 77 Ů.!..O...můS@.Ww 50 18 22 10 11 21 00 00 0b 00 00 00 18 00 00 00 P."..!.......... 25 2b 08 00 a0 10 5d 01 04 00 00 00 64 66 67 64 %+....].....dfgd 73 66 67 65 61 67 68 00 sfgeagh. 22:35:01.470269 cos.gadu-gadu.pl.8074 > 10.0.0.3.1615: P 40:60(20) ack 110 win 17411 (DF) (ttl 115, id 52486) 45 00 00 3c cd 06 40 00 73 06 36 8c d9 11 21 15 E..<Í.@.s.6.Ů.!. 0a 00 00 03 1f 8a 06 4f 40 05 57 77 00 6d f9 73 .......O@.Ww.můs 50 18 44 03 73 18 00 00 05 00 00 00 0c 00 00 00 P.D.s........... 02 00 00 00 25 2b 08 00 a0 10 5d 01 ....%+....]. 22:35:17.573801 10.0.0.3.1615 > cos.gadu-gadu.pl.8074: P 110:141(31) ack 60 win 8700 (DF) (ttl 32, id 8218) 45 00 00 47 20 1a 40 00 20 06 36 6e 0a 00 00 03 E..G .@. .6n.... d9 11 21 15 06 4f 1f 8a 00 6d f9 73 40 05 57 8b Ů.!..O...můs@.W. 50 18 21 fc 32 f2 00 00 0b 00 00 00 17 00 00 00 P.!ü2ň.......... 25 2b 08 00 d0 1b 5d 01 04 00 00 00 76 62 6e 66 %+..Đ.].....vbnf 67 68 6a 67 68 6a 00 ghjghj. 22:35:18.045120 cos.gadu-gadu.pl.8074 > 10.0.0.3.1615: P 60:80(20) ack 141 win 17380 (DF) (ttl 115, id 1009) 45 00 00 3c 03 f1 40 00 73 06 ff a1 d9 11 21 15 E..<.ń@.s.˙ĄŮ.!. 0a 00 00 03 1f 8a 06 4f 40 05 57 8b 00 6d f9 92 .......O@.W..mů. 50 18 43 e4 42 f9 00 00 05 00 00 00 0c 00 00 00 P.CäBů.......... 02 00 00 00 25 2b 08 00 d0 1b 5d 01 ....%+..Đ.]. ekg-1.9~pre+r2855/dumps/gg/8.https.txt000066400000000000000000000005551174410337000174220ustar00rootroot00000000000000gg_https_hello klient -> a1 2d 90 00 01 0e 00 00 00 8a 1f 32 31 37 2e 31 37 2e 33 33 2e 32 31 gg_https_ok serwer -> a1 2d 90 00 03 01 00 00 00 gg_https_send_hash klient -> a1 2d 90 00 04 01 00 00 00 ------------------------------------------------------------------------------ no i normalnie lecimy ;> serwer -> 01 00 00 00 04 00 00 00 02 56 00 00 ekg-1.9~pre+r2855/dumps/gg/ctcp-msg000066400000000000000000000002011174410337000167750ustar00rootroot00000000000000początek komunikacji między klientami. wysyłają sobie uiny. < 00000000 51 12 14 00 25 2b 08 00 Q...%+.. ekg-1.9~pre+r2855/dumps/gg/gg-file-transfer-from-lookas-to-arekm.ethereal.txt000066400000000000000000000154241174410337000270030ustar00rootroot0000000000000000:39:26.460113 lookas.1692 > 217.17.41.82.8074: P 304994290:304994311(21) ack 518533656 win 17375 (DF) 0x0000 4500 003d dd46 4000 8006 9286 9c11 ec78 E..=.F@........x 0x0010 d911 2952 069c 1f8a 122d d7f2 1ee8 3218 ..)R.....-....2. 0x0020 5018 43df 098d 0000>0b00 0000 0d00 0000 P.C............. 0x0030 3017 1c00 0000 0000 1000 0000 02 0............ 00:39:26.520915 217.17.41.82.8074 > arm.1504: P 902134175:902134200(25) ack 1524957245 win 17462 (DF) 0x0000 4500 004d 65f7 4000 7a06 0fd5 d911 2952 E..Me.@.z.....)R 0x0010 9c11 ec69 1f8a 05e0 35c5 799f 5ae5 003d ...i....5.y.Z..= 0x0020 8018 4436 4229 0000 0101 080a 0062 2d11 ..D6B).......b-. 0x0030 0015 33da>0a00 0000 1100 0000 32bf 0700 ..3.........2... 0x0040 0000 0000 610f 0c3c 1000 0000 02 ....a..<..... 00:39:26.522474 217.17.41.82.8074 > lookas.1692: P 1:21(20) ack 21 win 17383 (DF) 0x0000 4500 003c 65f9 4000 7a06 0fd5 d911 2952 E..0500 0000 0c00 0000 P.C..q.......... 0x0030 0200 0000 3017 1c00 0000 0000 ....0....... 00:39:27.004611 arm.1505 > lookas.1550: S 1605291199:1605291199(0) win 5840 (DF) 0x0000 4500 003c f6e9 4000 4006 32cd 9c11 ec69 E..<..@.@.2....i 0x0010 9c11 ec78 05e1 060e 5fae ccbf 0000 0000 ...x...._....... 0x0020 a002 16d0 ad69 0000 0204 05b4 0402 080a .....i.......... 0x0030 0015 3a56 0000 0000 0103 0300 ..:V........ 00:39:27.008812 lookas.1550 > arm.1505: S 343509975:343509975(0) ack 1605291200 win 17520 (DF) 0x0000 4500 0040 dd63 4000 8006 0c4f 9c11 ec78 E..@.c@....O...x 0x0010 9c11 ec69 060e 05e1 1479 8bd7 5fae ccc0 ...i.....y.._... 0x0020 b012 4470 07cd 0000 0204 05b4 0103 0300 ..Dp............ 0x0030 0101 080a 0000 0000 0000 0000 0101 0402 ................ 00:39:27.017480 arm.1505 > lookas.1550: P 1:5(4) ack 1 win 5840 (DF) 0x0000 4500 0038 f6eb 4000 4006 32cf 9c11 ec69 E..8..@.@.2....i 0x0010 9c11 ec78 05e1 060e 5fae ccc0 1479 8bd8 ...x...._....y.. 0x0020 8018 16d0 efa8 0000 0101 080a 0015 3a57 ..............:W 0x0030 0000 0000>3017 1c00 ....0... 00:39:27.156244 arm.1505 > lookas.1550: P 5:9(4) ack 1 win 5840 (DF) 0x0000 4500 0038 f6ec 4000 4006 32ce 9c11 ec69 E..8..@.@.2....i 0x0010 9c11 ec78 05e1 060e 5fae ccc4 1479 8bd8 ...x...._....y.. 0x0020 8018 16d0 6bb0 0000 0101 080a 0015 3a65 ....k.........:e 0x0030 000c 9632>32bf 0700 ...22... 00:39:27.157440 lookas.1550 > arm.1505: P 1:5(4) ack 9 win 17512 (DF) 0x0000 4500 0038 dd69 4000 8006 0c51 9c11 ec78 E..8.i@....Q...x 0x0010 9c11 ec69 060e 05e1 1479 8bd8 5fae ccc8 ...i.....y.._... 0x0020 8018 4468 e147 0000 0101 080a 000c 9632 ..Dh.G.........2 0x0030 0015 3a65>5544 4147 ..:eUDAG 00:39:27.610368 arm.1505 > lookas.1550: P 9:13(4) ack 5 win 5840 (DF) 0x0000 4500 0038 f6ee 4000 4006 32cc 9c11 ec69 E..8..@.@.2....i 0x0010 9c11 ec78 05e1 060e 5fae ccc8 1479 8bdc ...x...._....y.. 0x0020 8018 16d0 a239 0000 0101 080a 0015 3a93 .....9........:. 0x0030 000c 9632>0300 0000 ...2.... 00:39:27.619637 lookas.1550 > arm.1505: P 5:9(4) ack 13 win 17508 (DF) 0x0000 4500 0038 dd85 4000 8006 0c35 9c11 ec78 E..8..@....5...x 0x0010 9c11 ec69 060e 05e1 1479 8bdc 5fae cccc ...i.....y.._... 0x0020 8018 4464 769d 0000 0101 080a 000c 9636 ..Ddv..........6 0x0030 0015 3a93>0100 0000 ..:..... 00:39:38.561657 lookas.1550 > arm.1505: P 9:341(332) ack 13 win 17508 (DF) 0x0000 4500 0180 df3f 4000 8006 0933 9c11 ec78 E....?@....3...x 0x0010 9c11 ec69 060e 05e1 1479 8be0 5fae cccc ...i.....y.._... 0x0020 8018 4464 d084 0000 0101 080a 000c 96a3 ..Dd............ 0x0030 0015 3a93>0300 0000 0000 0000 0000 0000 ..:............. 0x0040 2000 0000 202b c73c 537c c101 0018 0f3c .....+. lookas.1550: P 13:25(12) ack 341 win 6432 (DF) 0x0000 4500 0040 f6f1 4000 4006 32c1 9c11 ec69 E..@..@.@.2....i 0x0010 9c11 ec78 05e1 060e 5fae cccc 1479 8d2c ...x...._....y., 0x0020 8018 1920 8fc1 0000 0101 080a 0015 45ee ..............E. 0x0030 000c 96a3>0600 0000 0000 0000 0000 0000 ................ 00:39:56.723241 lookas.1550 > arm.1505: P 341:369(28) ack 25 win 17496 (DF) 0x0000 4500 0050 e634 4000 8006 036e 9c11 ec78 E..P.4@....n...x 0x0010 9c11 ec69 060e 05e1 1479 8d2c 5fae ccd8 ...i.....y.,_... 0x0020 8018 4458 d2ca 0000 0101 080a 000c 9759 ..DX...........Y 0x0030 0015 45ee>0200 0000 1000 0000 0000 0000 ..E............. 0x0040 5a41 5741 5254 4f53 4320 504c 494b 550a ZAWARTOSC.PLIKU. 00:39:57.400884 arm.1505 > lookas.1550: F 25:25(0) ack 369 win 6432 (DF) 0x0000 4500 0034 f6f3 4000 4006 32cb 9c11 ec69 E..4..@.@.2....i 0x0010 9c11 ec78 05e1 060e 5fae ccd8 1479 8d48 ...x...._....y.H 0x0020 8011 1920 94ae 0000 0101 080a 0015 4636 ..............F6 0x0030 000c 9759 ...Y 00:39:57.412642 lookas.1550 > arm.1505: F 369:369(0) ack 26 win 17496 (DF) 0x0000 4500 0034 e6d7 4000 8006 02e7 9c11 ec78 E..4..@........x 0x0010 9c11 ec69 060e 05e1 1479 8d48 5fae ccd9 ...i.....y.H_... 0x0020 8011 4458 696e 0000 0101 080a 000c 9760 ..DXin.........` 0x0030 0015 4636 ..F6 ekg-1.9~pre+r2855/dumps/gg/gg-rozmowa-wyslanie-odbior.ethereal.txt000066400000000000000000000025071174410337000250770ustar00rootroot0000000000000019:04:20.811855 lookas.4678 > 217.17.41.84.8074: P 1963603708:1963603742(34) ack 1378904407 win 17404 (DF) 0x0000 4500 004a b7b9 4000 8006 b804 9c11 ec78 E..J..@........x 0x0010 d911 2954 1246 1f8a 750a 36fc 5230 6957 ..)T.F..u.6.R0iW 0x0020 5018 43fc 47fd 0000>0b00 0000 1a00 0000 P.C.G........... 0x0030 e8c3 1300 0026 c900 2800 0000 7465 7374 .....&..(...test 0x0040 0001 0100 0000 fe9c 0600 .......... 19:04:20.811946 lookas.4678 > 217.17.41.84.8074: P 34:68(34) ack 1 win 17404 (DF) 0x0000 4500 004a b7ba 4000 8006 b803 9c11 ec78 E..J..@........x 0x0010 d911 2954 1246 1f8a 750a 371e 5230 6957 ..)T.F..u.7.R0iW 0x0020 5018 43fc 47db 0000>0b00 0000 1a00 0000 P.C.G........... 0x0030 fe9c 0600 0026 c900 2800 0000 7465 7374 .....&..(...test 0x0040 0001 0100 0000 e8c3 1300 .......... 19:04:20.907550 217.17.41.84.8074 > arm.2713: P 2910852030:2910852068(38) ack 975904688 win 16843 (DF) 0x0000 4500 005a 1cf3 4000 7a06 58ca d911 2954 E..Z..@.z.X...)T 0x0010 9c11 ec69 1f8a 0a99 ad80 13be 3a2b 1fb0 ...i........:+.. 0x0020 8018 41cb f4a4 0000 0101 080a 0028 a257 ..A..........(.W 0x0030 0075 4d03>0a00 0000 1e00 0000 32bf 0700 .uM.........2... 0x0040 0026 c900 556f 0a3c 0800 0000 7465 7374 .&..Uo.<....test 0x0050 0001 0100 0000 fe9c 0600 .......... ekg-1.9~pre+r2855/dumps/http/000077500000000000000000000000001174410337000157265ustar00rootroot00000000000000ekg-1.9~pre+r2855/dumps/http/change.txt000066400000000000000000000011371174410337000177160ustar00rootroot00000000000000--8<-- POST /appsvc/fmpubreg2.asp HTTP/1.0 Host: pubdir.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.7 [en] (Win98; I) Content-Length: 145 Pragma: no-cache FmNum=1315409&Pass=nowehaslo&FirstName=ia&LastName=nazwiskoaa&NickName=pseudoaa&Email=3232&BirthYear=1901&Gender=1&City=sssss&Phone=%2B4832892890 --8<-- HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Wed, 22 Aug 2001 12:13:30 GMT Connection: Keep-Alive Content-Length: 12 Content-Type: text/html Set-Cookie: ASPSESSIONIDGQGQGNUC=IDEIGJMBDCOKNEHAKJBLNHMN; path=/ Cache-control: private reg_success: --8<-- ekg-1.9~pre+r2855/dumps/http/chpasswd.txt000066400000000000000000000010551174410337000203040ustar00rootroot00000000000000--8<-- POST /appsvc/fmregister.asp HTTP/1.0 Host: register.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.7 [en] (Win98; I) Content-Length: 86 Pragma: no-cache fmnumber=1315409&fmpwd=dupa123&pwd=nowehaslo&email=nowy%2Demail@irc.pl&code=1500343197 --8<-- HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Wed, 22 Aug 2001 12:12:35 GMT Connection: Keep-Alive Content-Length: 19 Content-Type: text/html Set-Cookie: ASPSESSIONIDGQGQGNUC=BFCIGJMBAKIKBENLCEOLEDBH; path=/ Cache-control: private reg_success:1315409 --8<-- ekg-1.9~pre+r2855/dumps/http/imp-exp.txt000066400000000000000000000033461174410337000200540ustar00rootroot00000000000000--8<-- Eksport userow na serwer: POST /appsvc/fmcontactsput.asp HTTP/1.0 Host: pubdir.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT) Content-Length: 306 Pragma: no-cache FmNum=1840944&Pass=d&Contacts=ImieArekm%3BNazwiskoArekm%3BPseudoArekm%3Barekm%3B%2B4860412121212%3Bgrupa_nr_1%3B1295336%0D%0AImieLookas%3BNazwiskoLookas%3BPseudoLookas%3BLookas%3B%2B48997%3B%3B507698%0D%0AImieKtos%3BNazwiskoKtos%3BPseudoKtos%3BKtos%3B%2B48602003456%3Bgrupa_nr_1%2Cgrupa_nr_2%3B123456%0D%0A HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Thu, 22 Nov 2001 17:02:32 GMT Connection: Keep-Alive Content-Length: 12 Content-Type: text/html Cache-control: private put_success: --8<-- Import userow z serwera POST /appsvc/fmcontactsget.asp HTTP/1.0 Host: pubdir.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT) Content-Length: 20 Pragma: no-cache FmNum=1840944&Pass=d HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Thu, 22 Nov 2001 17:02:39 GMT Connection: Keep-Alive Content-Length: 232 Content-Type: text/html Cache-control: private get_results:ImieArekm;NazwiskoArekm;PseudoArekm;arekm;+4860412121212;grupa_nr_1;1295336 ImieLookas;NazwiskoLookas;PseudoLookas;Lookas;+48997;;507698 ImieKtos;NazwiskoKtos;PseudoKtos;Ktos;+48602003456;grupa_nr_1,grupa_nr_2;123456 --8<-- Kasacja userlisty: FmNum=1840944&Pass=d&Delete=1 --8<-- robione z uina: 1840505 userlista: lookas = 507698 (nie nalezy do zadnej grupy) arekm = 1295336 (grupy: grupa_nr_1) ktos = 123456 (grupy: grupa_nr1,grupa_nr_2) ImieXXX, NazwiskoXXX, PseudoXXX ... - odpowiednio pola w interfejsie windzianego klienta gg XXX - pole Wyswietlanie ekg-1.9~pre+r2855/dumps/http/init.txt000066400000000000000000000003371174410337000174350ustar00rootroot00000000000000--8<-- GET /appsvc/appmsg.asp?fmnumber=535333 HTTP/1.0 Host: appmsg.gadu-gadu.pl User-Agent: Mozilla/4.7 [en] (Win98; I) Pragma: no-cache --8<-- HTTP/1.0 200 OK 0 1 0 217.17.33.21:8074 217.17.33.21 217.17.33.21 --8<-- ekg-1.9~pre+r2855/dumps/http/new-uin.txt000066400000000000000000000021241174410337000200500ustar00rootroot00000000000000--8<-- POST /appsvc/fmregister.asp HTTP/1.0 Host: register.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.7 [en] (Win98; I) Content-Length: 48 Pragma: no-cache pwd=dupa123&email=wojtekka@irc.pl&code=863968097 --8<-- HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Wed, 22 Aug 2001 12:02:08 GMT Connection: Keep-Alive Content-Length: 19 Content-Type: text/html Set-Cookie: ASPSESSIONIDGQGQGNUC=GELGGJMBGGEDGNGPHBGGHLEC; path=/ Cache-control: private reg_success:1315409 --8<-- POST /appsvc/fmpubreg2.asp HTTP/1.0 Host: pubdir.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.7 [en] (Win98; I) Content-Length: 135 Pragma: no-cache FmNum=1315409&Pass=dupa123&FirstName=imie&LastName=nazwisko&NickName=pseudo&Email=email&BirthYear=1900&Gender=2&City=miejscowosc&Phone= --8<-- HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Wed, 22 Aug 2001 12:03:28 GMT Connection: Keep-Alive Content-Length: 12 Content-Type: text/html Set-Cookie: ASPSESSIONIDGQGQGNUC=KEOGGJMBDKMGDIOAGEHLOIPM; path=/ Cache-control: private reg_success: --8<-- ekg-1.9~pre+r2855/dumps/http/passwd.txt000066400000000000000000000137251174410337000200000ustar00rootroot0000000000000014:02:13.163825 P 213.146.38.151.1054 > 217.17.33.22.www: S 1152612:1152612(0) win 8192 (DF) (ttl 128, id 52482) 45 00 00 30 cd 02 40 00 80 06 37 74 d5 92 26 97 E..0Í.@...7tŐ.&. d9 11 21 16 04 1e 00 50 00 11 96 64 00 00 00 00 Ů.!....P...d.... 70 02 20 00 d1 ea 00 00 02 04 05 b4 01 01 04 02 p. .Ńę.....´.... 14:02:16.144808 P 213.146.38.151.1054 > 217.17.33.22.www: S 1152612:1152612(0) win 8192 (DF) (ttl 128, id 52738) 45 00 00 30 ce 02 40 00 80 06 36 74 d5 92 26 97 E..0Î.@...6tŐ.&. d9 11 21 16 04 1e 00 50 00 11 96 64 00 00 00 00 Ů.!....P...d.... 70 02 20 00 d1 ea 00 00 02 04 05 b4 01 01 04 02 p. .Ńę.....´.... 14:02:16.351983 P 217.17.33.22.www > 213.146.38.151.1054: S 1968818111:1968818111(0) ack 1152613 win 17520 (DF) (ttl 123, id 11780) 45 00 00 30 2e 04 40 00 7b 06 db 72 d9 11 21 16 E..0..@.{.ŰrŮ.!. d5 92 26 97 00 50 04 1e 75 59 c7 bf 00 11 96 65 Ő.&..P..uYÇż...e 70 12 44 70 70 50 00 00 02 04 05 b4 01 01 04 02 p.DppP.....´.... 14:02:16.352629 P 213.146.38.151.1054 > 217.17.33.22.www: . 1:1(0) ack 1 win 8760 (DF) (ttl 128, id 52994) 45 00 00 28 cf 02 40 00 80 06 35 7c d5 92 26 97 E..(Ď.@...5|Ő.&. d9 11 21 16 04 1e 00 50 00 11 96 65 75 59 c7 c0 Ů.!....P...euYÇŔ 50 10 22 38 bf 4c 00 00 00 00 00 00 00 00 P."8żL........ 14:02:16.354740 P 213.146.38.151.1054 > 217.17.33.22.www: P 1:284(283) ack 1 win 8760 (DF) (ttl 128, id 53250) 45 00 01 43 d0 02 40 00 80 06 33 61 d5 92 26 97 E..CĐ.@...3aŐ.&. d9 11 21 16 04 1e 00 50 00 11 96 65 75 59 c7 c0 Ů.!....P...euYÇŔ 50 18 22 38 b2 7e 00 00 50 4f 53 54 20 2f 61 70 P."8˛~..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 37 20 5b 65 6e 5d 20 28 57 69 6e 39 38 3b 4.7 [en] (Win98; 20 49 29 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e I)..Content-Len 67 74 68 3a 20 38 36 0d 0a 50 72 61 67 6d 61 3a gth: 86..Pragma: 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a 66 6d 6e no-cache....fmn 75 6d 62 65 72 3d 31 33 31 35 34 30 39 26 66 6d umber=1315409&fm 70 77 64 3d 64 75 70 61 31 32 33 26 70 77 64 3d pwd=dupa123&pwd= 6e 6f 77 65 68 61 73 6c 6f 26 65 6d 61 69 6c 3d nowehaslo&email= 6e 6f 77 79 25 32 44 65 6d 61 69 6c 40 69 72 63 nowy%2Demail@irc 2e 70 6c 26 63 6f 64 65 3d 31 35 30 30 33 34 33 .pl&code=1500343 31 39 37 197 14:02:16.354770 P 217.17.33.22.www > 213.146.38.151.1054: . 1:1(0) ack 1 win 17520 (DF) (ttl 123, id 11789) 45 00 00 28 2e 0d 40 00 7b 06 db 71 d9 11 21 16 E..(..@.{.ŰqŮ.!. d5 92 26 97 00 50 04 1e 75 59 c7 c0 00 11 96 65 Ő.&..P..uYÇŔ...e 50 10 44 70 9d 14 00 00 02 04 05 b4 01 01 P.Dp.......´.. 14:02:16.715931 P 217.17.33.22.www > 213.146.38.151.1054: . 1:1(0) ack 284 win 17237 (DF) (ttl 123, id 12021) 45 00 00 28 2e f5 40 00 7b 06 da 89 d9 11 21 16 E..(.ő@.{.Ú.Ů.!. d5 92 26 97 00 50 04 1e 75 59 c7 c0 00 11 97 80 Ő.&..P..uYÇŔ.... 50 10 43 55 9d 14 00 00 7f df 20 ed 19 df P.CU.....ß í.ß 14:02:16.833772 P 217.17.33.22.www > 213.146.38.151.1054: P 1:263(262) ack 284 win 17237 (DF) (ttl 123, id 12118) 45 00 01 2e 2f 56 40 00 7b 06 d9 22 d9 11 21 16 E.../V@.{.Ů"Ů.!. d5 92 26 97 00 50 04 1e 75 59 c7 c0 00 11 97 80 Ő.&..P..uYÇŔ.... 50 18 43 55 c9 92 00 00 48 54 54 50 2f 31 2e 31 P.CUÉ...HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 57 65 64 2c 20 32 .0..Date: Wed, 2 32 20 41 75 67 20 32 30 30 31 20 31 32 3a 31 32 2 Aug 2001 12:12 3a 33 35 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :35 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 51 47 51 47 4e 55 43 3d 42 SIONIDGQGQGNUC=B 46 43 49 47 4a 4d 42 41 4b 49 4b 42 45 4e 4c 43 FCIGJMBAKIKBENLC 45 4f 4c 45 44 42 48 3b 20 70 61 74 68 3d 2f 0d EOLEDBH; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 33 31 35 34 30 39 uccess:1315409 14:02:16.833803 P 217.17.33.22.www > 213.146.38.151.1054: F 263:263(0) ack 284 win 17237 (DF) (ttl 123, id 12119) 45 00 00 28 2f 57 40 00 7b 06 da 27 d9 11 21 16 E..(/W@.{.Ú'Ů.!. d5 92 26 97 00 50 04 1e 75 59 c8 c6 00 11 97 80 Ő.&..P..uYČĆ.... 50 11 43 55 9c 0d 00 00 48 54 54 50 2f 31 P.CU....HTTP/1 14:02:16.834412 P 213.146.38.151.1054 > 217.17.33.22.www: . 284:284(0) ack 264 win 8498 (DF) (ttl 128, id 53506) 45 00 00 28 d1 02 40 00 80 06 33 7c d5 92 26 97 E..(Ń.@...3|Ő.&. d9 11 21 16 04 1e 00 50 00 11 97 80 75 59 c8 c7 Ů.!....P....uYČÇ 50 10 21 32 be 30 00 00 00 00 00 00 00 00 P.!2ž0........ 14:02:16.836114 P 213.146.38.151.1054 > 217.17.33.22.www: F 284:284(0) ack 264 win 8498 (DF) (ttl 128, id 53762) 45 00 00 28 d2 02 40 00 80 06 32 7c d5 92 26 97 E..(Ň.@...2|Ő.&. d9 11 21 16 04 1e 00 50 00 11 97 80 75 59 c8 c7 Ů.!....P....uYČÇ 50 11 21 32 be 2f 00 00 00 00 00 00 00 00 P.!2ž/........ 14:02:17.104578 P 217.17.33.22.www > 213.146.38.151.1054: . 264:264(0) ack 285 win 17237 (DF) (ttl 123, id 12260) 45 00 00 28 2f e4 40 00 7b 06 d9 9a d9 11 21 16 E..(/ä@.{.Ů.Ů.!. d5 92 26 97 00 50 04 1e 75 59 c8 c7 00 11 97 81 Ő.&..P..uYČÇ.... 50 10 43 55 9c 0c 00 00 ed 48 53 39 27 b7 P.CU....íHS9'ˇ ekg-1.9~pre+r2855/dumps/http/passwd2.txt000066400000000000000000000010341174410337000200500ustar00rootroot00000000000000--8<-- POST /appsvc/fmpubdetails2.asp HTTP/1.0 Host: pubdir.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.7 [en] (Win98; I) Content-Length: 28 Pragma: no-cache FmNum=1315409&Pass=nowehaslo --8<-- HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Wed, 22 Aug 2001 12:13:00 GMT Connection: Keep-Alive Content-Length: 70 Content-Type: text/html Set-Cookie: ASPSESSIONIDGQGQGNUC=CBDIGJMBJJNEAHFMFGMECKHN; path=/ Cache-control: private query_result: imie nazwisko pseudo email 1900 2 miejscowosc --8<-- ekg-1.9~pre+r2855/dumps/http/remind.txt000066400000000000000000000004211174410337000177420ustar00rootroot00000000000000przypomnienie hasła: --8<-- POST /appsvc/fmsendpwd.asp HTTP/1.0 Host: retr.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT) Content-Length: 28 Pragma: no-cache userid=123456&code=896294500 --8<-- ekg-1.9~pre+r2855/dumps/http/search.txt000066400000000000000000000016071174410337000177400ustar00rootroot00000000000000to tylko jeden z trybów szukania. inne to: Mode=1&Email=costam Mode=2&MobilePhone=costam Mode=3&UserId=costam do każdego można dorzucić ,,&ActiveOnly='' na końcu. --8<-- POST /appsvc/fmpubquery2.asp HTTP/1.0 Host: pubdir.gadu-gadu.pl Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.7 [en] (Win98; I) Content-Length: 88 Pragma: no-cache Mode=0&FirstName=Agata&LastName=&NickName=&Gender=1&City=Bydgoszcz&MinBirth=0&MaxBirth=0 --8<-- HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Sat, 17 Feb 2001 11:55:00 GMT Connection: Keep-Alive Content-Length: 231 Content-Type: text/html Set-Cookie: ASPSESSIONIDQGQQGZZG=GFIPABHCACKEBGLGGMLAHGMF; path=/ Cache-control: private query_results: 1 343409 Agata blacky 0 1 Bydgoszcz 1 83706 agata górska agata bernadeta 0 1 bydgoszcz 1 630032 Agata Rutkowska Czika 1983 1 Bydgoszcz 1 446404 Agata Bloch bloszka 1986 1 Bydgoszcz --8<-- ekg-1.9~pre+r2855/dumps/reg-hashes/000077500000000000000000000000001174410337000167755ustar00rootroot00000000000000ekg-1.9~pre+r2855/dumps/reg-hashes/bar000066400000000000000000000227161174410337000174740ustar00rootroot0000000000000018:46:32.553551 10.0.0.3.1034 > 217.17.33.22.80: S 282725:282725(0) win 8192 (DF) 45 00 00 30 31 00 40 00 80 06 c5 9d 0a 00 00 03 E..01.@...Ĺ..... d9 11 21 16 04 0a 00 50 00 04 50 65 00 00 00 00 Ů.!....P..Pe.... 70 02 20 00 0a 32 00 00 02 04 05 b4 01 01 04 02 p. ..2.....´.... 18:46:33.030160 217.17.33.22.80 > 10.0.0.3.1034: S 2431281379:2431281379(0) ack 282726 win 17520 (DF) 45 00 00 30 b9 58 40 00 75 06 48 45 d9 11 21 16 E..0šX@.u.HEŮ.!. 0a 00 00 03 00 50 04 0a 90 ea 68 e3 00 04 50 66 .....P...ęhă..Pf 70 12 44 70 eb e2 00 00 02 04 05 b4 01 01 04 02 p.Dpëâ.....´.... 18:46:33.030854 10.0.0.3.1034 > 217.17.33.22.80: . ack 1 win 8760 (DF) 45 00 00 28 32 00 40 00 80 06 c4 a5 0a 00 00 03 E..(2.@...ÄĽ.... d9 11 21 16 04 0a 00 50 00 04 50 66 90 ea 68 e4 Ů.!....P..Pf.ęhä 50 10 22 38 3a df 00 00 20 20 20 20 20 20 P."8:ß.. 18:46:33.032600 10.0.0.3.1034 > 217.17.33.22.80: P 1:252(251) ack 1 win 8760 (DF) 45 00 01 23 33 00 40 00 80 06 c2 aa 0a 00 00 03 E..#3.@...ÂŞ.... d9 11 21 16 04 0a 00 50 00 04 50 66 90 ea 68 e4 Ů.!....P..Pf.ęhä 50 18 22 38 3f a9 00 00 50 4f 53 54 20 2f 61 70 P."8?Š..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 4e 54 29 0d 0a 43 6f 6e 74 65 6e 74 2d ws NT)..Content- 4c 65 6e 67 74 68 3a 20 33 35 0d 0a 50 72 61 67 Length: 35..Prag 6d 61 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a ma: no-cache.... 70 77 64 3d 61 26 65 6d 61 69 6c 3d 61 61 40 61 pwd=a&email=aa@a 2e 70 6c 26 63 6f 64 65 3d 31 30 34 33 32 32 32 .pl&code=1043222 38 35 30 850 18:46:33.830149 217.17.33.22.80 > 10.0.0.3.1034: P 1:263(262) ack 252 win 17269 (DF) 45 00 01 2e bb e5 40 00 75 06 44 ba d9 11 21 16 E...ťĺ@.u.DşŮ.!. 0a 00 00 03 00 50 04 0a 90 ea 68 e4 00 04 51 61 .....P...ęhä..Qa 50 18 43 75 2c ff 00 00 48 54 54 50 2f 31 2e 31 P.Cu,˙..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 35 20 4f 63 74 20 32 30 30 31 20 31 36 3a 34 34 5 Oct 2001 16:44 3a 34 38 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :48 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 51 47 51 51 59 49 4f 3d 4a SIONIDGQGQQYIO=J 41 50 44 43 4c 48 42 47 47 45 4a 46 42 4c 42 45 APDCLHBGGEJFBLBE 4c 4f 4d 41 42 4e 47 3b 20 70 61 74 68 3d 2f 0d LOMABNG; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 36 30 37 36 32 33 uccess:1607623 18:46:33.830280 217.17.33.22.80 > 10.0.0.3.1034: F 263:263(0) ack 252 win 17269 (DF) 45 00 00 28 bb e6 40 00 75 06 45 bf d9 11 21 16 E..(ťć@.u.EżŮ.!. 0a 00 00 03 00 50 04 0a 90 ea 69 ea 00 04 51 61 .....P...ęię..Qa 50 11 43 75 17 a0 00 00 P.Cu.... 18:46:33.831558 10.0.0.3.1034 > 217.17.33.22.80: . ack 264 win 8498 (DF) 45 00 00 28 34 00 40 00 80 06 c2 a5 0a 00 00 03 E..(4.@...ÂĽ.... d9 11 21 16 04 0a 00 50 00 04 51 61 90 ea 69 eb Ů.!....P..Qa.ęië 50 10 21 32 39 e3 00 00 20 20 20 20 20 20 P.!29ă.. 18:46:33.832451 10.0.0.3.1034 > 217.17.33.22.80: F 252:252(0) ack 264 win 8498 (DF) 45 00 00 28 35 00 40 00 80 06 c1 a5 0a 00 00 03 E..(5.@...ÁĽ.... d9 11 21 16 04 0a 00 50 00 04 51 61 90 ea 69 eb Ů.!....P..Qa.ęië 50 11 21 32 39 e2 00 00 20 20 20 20 20 20 P.!29â.. 18:46:34.210172 217.17.33.22.80 > 10.0.0.3.1034: . ack 253 win 17269 (DF) 45 00 00 28 be 0a 40 00 75 06 43 9b d9 11 21 16 E..(ž.@.u.C.Ů.!. 0a 00 00 03 00 50 04 0a 90 ea 69 eb 00 04 51 62 .....P...ęië..Qb 50 10 43 75 17 9f 00 00 P.Cu.... 18:46:50.233658 10.0.0.3.1036 > 217.17.33.22.80: S 300408:300408(0) win 8192 (DF) 45 00 00 30 37 00 40 00 80 06 bf 9d 0a 00 00 03 E..07.@...ż..... d9 11 21 16 04 0c 00 50 00 04 95 78 00 00 00 00 Ů.!....P...x.... 70 02 20 00 c5 1c 00 00 02 04 05 b4 01 01 04 02 p. .Ĺ......´.... 18:46:50.490159 217.17.33.22.80 > 10.0.0.3.1036: S 2571166212:2571166212(0) ack 300409 win 17520 (DF) 45 00 00 30 fb 97 40 00 75 06 06 06 d9 11 21 16 E..0ű.@.u...Ů.!. 0a 00 00 03 00 50 04 0c 99 40 e2 04 00 04 95 79 .....P...@â....y 70 12 44 70 25 56 00 00 02 04 05 b4 01 01 04 02 p.Dp%V.....´.... 18:46:50.490872 10.0.0.3.1036 > 217.17.33.22.80: . ack 1 win 8760 (DF) 45 00 00 28 38 00 40 00 80 06 be a5 0a 00 00 03 E..(8.@...žĽ.... d9 11 21 16 04 0c 00 50 00 04 95 79 99 40 e2 05 Ů.!....P...y.@â. 50 10 22 38 74 52 00 00 20 20 20 20 20 20 P."8tR.. 18:46:50.492346 10.0.0.3.1036 > 217.17.33.22.80: P 1:251(250) ack 1 win 8760 (DF) 45 00 01 22 39 00 40 00 80 06 bc ab 0a 00 00 03 E.."9.@...źŤ.... d9 11 21 16 04 0c 00 50 00 04 95 79 99 40 e2 05 Ů.!....P...y.@â. 50 18 22 38 13 d0 00 00 50 4f 53 54 20 2f 61 70 P."8.Đ..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 39 38 29 0d 0a 43 6f 6e 74 65 6e 74 2d ws 98)..Content- 4c 65 6e 67 74 68 3a 20 33 34 0d 0a 50 72 61 67 Length: 34..Prag 6d 61 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a ma: no-cache.... 70 77 64 3d 61 61 26 65 6d 61 69 6c 3d 61 40 61 pwd=aa&email=a@a 2e 70 6c 26 63 6f 64 65 3d 37 39 33 37 36 33 33 .pl&code=7937633 35 35 55 18:46:50.970242 217.17.33.22.80 > 10.0.0.3.1036: . ack 251 win 17270 (DF) 45 00 00 28 fd 8d 40 00 75 06 04 18 d9 11 21 16 E..(ý.@.u...Ů.!. 0a 00 00 03 00 50 04 0c 99 40 e2 05 00 04 96 73 .....P...@â....s 50 10 43 76 52 1a 00 00 P.CvR... 18:46:57.870200 217.17.33.22.80 > 10.0.0.3.1036: P 1:263(262) ack 251 win 17270 (DF) 45 00 01 2e 17 37 40 00 75 06 e9 68 d9 11 21 16 E....7@.u.éhŮ.!. 0a 00 00 03 00 50 04 0c 99 40 e2 05 00 04 96 73 .....P...@â....s 50 18 43 76 34 95 00 00 48 54 54 50 2f 31 2e 31 P.Cv4...HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 35 20 4f 63 74 20 32 30 30 31 20 31 36 3a 34 35 5 Oct 2001 16:45 3a 31 32 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :12 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 51 47 51 51 59 49 4f 3d 4a SIONIDGQGQQYIO=J 4c 50 44 43 4c 48 42 47 4c 49 4f 45 50 42 4d 41 LPDCLHBGLIOEPBMA 4a 43 4e 41 45 41 4f 3b 20 70 61 74 68 3d 2f 0d JCNAEAO; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 36 30 37 36 32 36 uccess:1607626 18:46:57.872272 10.0.0.3.1036 > 217.17.33.22.80: F 251:251(0) ack 263 win 8498 (DF) 45 00 00 28 3a 00 40 00 80 06 bc a5 0a 00 00 03 E..(:.@...źĽ.... d9 11 21 16 04 0c 00 50 00 04 96 73 99 40 e3 0b Ů.!....P...s.@ă. 50 11 21 32 73 57 00 00 20 20 20 20 20 20 P.!2sW.. 18:46:57.890125 217.17.33.22.80 > 10.0.0.3.1036: F 263:263(0) ack 251 win 17270 (DF) 45 00 00 28 17 39 40 00 75 06 ea 6c d9 11 21 16 E..(.9@.u.ęlŮ.!. 0a 00 00 03 00 50 04 0c 99 40 e3 0b 00 04 96 73 .....P...@ă....s 50 11 43 76 51 13 00 00 P.CvQ... 18:46:57.890807 10.0.0.3.1036 > 217.17.33.22.80: . ack 264 win 8498 (DF) 45 00 00 28 3b 00 40 00 80 06 bb a5 0a 00 00 03 E..(;.@...ťĽ.... d9 11 21 16 04 0c 00 50 00 04 96 74 99 40 e3 0c Ů.!....P...t.@ă. 50 10 21 32 73 56 00 00 20 20 20 20 20 20 P.!2sV.. 18:46:58.190194 217.17.33.22.80 > 10.0.0.3.1036: . ack 252 win 17270 (DF) 45 00 00 28 18 86 40 00 75 06 e9 1f d9 11 21 16 E..(..@.u.é.Ů.!. 0a 00 00 03 00 50 04 0c 99 40 e3 0c 00 04 96 74 .....P...@ă....t 50 10 43 76 51 12 00 00 P.CvQ... ekg-1.9~pre+r2855/dumps/reg-hashes/foo000066400000000000000000000110411174410337000175000ustar00rootroot0000000000000018:44:52.683542 10.0.0.3.1032 > 217.17.33.22.80: S 182840:182840(0) win 8192 (DF) 45 00 00 30 2b 00 40 00 80 06 cb 9d 0a 00 00 03 E..0+.@...Ë..... d9 11 21 16 04 08 00 50 00 02 ca 38 00 00 00 00 Ů.!....P..Ę8.... 70 02 20 00 90 62 00 00 02 04 05 b4 01 01 04 02 p. ..b.....´.... 18:44:52.940166 217.17.33.22.80 > 10.0.0.3.1032: S 1506011515:1506011515(0) ack 182841 win 17520 (DF) 45 00 00 30 13 9a 40 00 75 06 ee 03 d9 11 21 16 E..0..@.u.î.Ů.!. 0a 00 00 03 00 50 04 08 59 c3 e9 7b 00 02 ca 39 .....P..YĂé{..Ę9 70 12 44 70 28 a2 00 00 02 04 05 b4 01 01 04 02 p.Dp(˘.....´.... 18:44:52.940890 10.0.0.3.1032 > 217.17.33.22.80: . ack 1 win 8760 (DF) 45 00 00 28 2c 00 40 00 80 06 ca a5 0a 00 00 03 E..(,.@...ĘĽ.... d9 11 21 16 04 08 00 50 00 02 ca 39 59 c3 e9 7c Ů.!....P..Ę9YĂé| 50 10 22 38 77 9e 00 00 20 20 20 20 20 20 P."8w... 18:44:52.942341 10.0.0.3.1032 > 217.17.33.22.80: P 1:238(237) ack 1 win 8760 (DF) 45 00 01 15 2d 00 40 00 80 06 c8 b8 0a 00 00 03 E...-.@...ȸ.... d9 11 21 16 04 08 00 50 00 02 ca 39 59 c3 e9 7c Ů.!....P..Ę9YĂé| 50 18 22 38 fa d6 00 00 50 4f 53 54 20 2f 61 70 P."8úÖ..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 37 20 5b 65 6e 5d 20 28 57 69 6e 39 38 3b 4.7 [en] (Win98; 20 49 29 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e I)..Content-Len 67 74 68 3a 20 34 30 0d 0a 50 72 61 67 6d 61 3a gth: 40..Pragma: 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a 70 77 64 no-cache....pwd 3d 25 32 31 26 65 6d 61 69 6c 3d 25 32 31 40 25 =%21&email=%21@% 32 31 2e 25 32 31 26 63 6f 64 65 3d 38 31 31 36 21.%21&code=8116 31 34 32 38 37 14287 18:44:53.500175 217.17.33.22.80 > 10.0.0.3.1032: P 1:263(262) ack 238 win 17283 (DF) 45 00 01 2e 15 9d 40 00 75 06 eb 02 d9 11 21 16 E.....@.u.ë.Ů.!. 0a 00 00 03 00 50 04 08 59 c3 e9 7c 00 02 cb 26 .....P..YĂé|..Ë& 50 18 43 83 34 cd 00 00 48 54 54 50 2f 31 2e 31 P.C.4Í..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 35 20 4f 63 74 20 32 30 30 31 20 31 36 3a 34 33 5 Oct 2001 16:43 3a 30 38 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :08 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 51 47 51 51 59 49 4f 3d 43 SIONIDGQGQQYIO=C 47 4b 44 43 4c 48 42 42 50 47 4e 4f 50 48 50 50 GKDCLHBBPGNOPHPP 4b 42 47 46 4f 48 49 3b 20 70 61 74 68 3d 2f 0d KBGFOHI; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 36 30 37 36 30 36 uccess:1607606 18:44:53.500307 217.17.33.22.80 > 10.0.0.3.1032: F 263:263(0) ack 238 win 17283 (DF) 45 00 00 28 15 a3 40 00 75 06 ec 02 d9 11 21 16 E..(.Ł@.u.ě.Ů.!. 0a 00 00 03 00 50 04 08 59 c3 ea 82 00 02 cb 26 .....P..YĂę...Ë& 50 11 43 83 54 5f 00 00 P.C.T_.. 18:44:53.501593 10.0.0.3.1032 > 217.17.33.22.80: . ack 264 win 8498 (DF) 45 00 00 28 2e 00 40 00 80 06 c8 a5 0a 00 00 03 E..(..@...ČĽ.... d9 11 21 16 04 08 00 50 00 02 cb 26 59 c3 ea 83 Ů.!....P..Ë&YĂę. 50 10 21 32 76 b0 00 00 20 20 20 20 20 20 P.!2v°.. 18:44:53.502476 10.0.0.3.1032 > 217.17.33.22.80: F 238:238(0) ack 264 win 8498 (DF) 45 00 00 28 2f 00 40 00 80 06 c7 a5 0a 00 00 03 E..(/.@...ÇĽ.... d9 11 21 16 04 08 00 50 00 02 cb 26 59 c3 ea 83 Ů.!....P..Ë&YĂę. 50 11 21 32 76 af 00 00 20 20 20 20 20 20 P.!2vŻ.. 18:44:53.840180 217.17.33.22.80 > 10.0.0.3.1032: . ack 239 win 17283 (DF) 45 00 00 28 17 01 40 00 75 06 ea a4 d9 11 21 16 E..(..@.u.ę¤Ů.!. 0a 00 00 03 00 50 04 08 59 c3 ea 83 00 02 cb 27 .....P..YĂę...Ë' 50 10 43 83 54 5e 00 00 P.C.T^.. ekg-1.9~pre+r2855/dumps/reg-hashes/hashes000066400000000000000000000036741174410337000202050ustar00rootroot00000000000000pwd=dupa123&email=wojtekka@irc.pl&code=863968097 pwd=dupa12&email=wojtekka@irc.pl&code=1614000681 pwd=dupa123&email=wojtekka@irc.p&code=1540905424 pwd=a&email=a@a.pl&code=456060607 pwd=ab&email=a@a.pl&code=793828635 pwd=!&email=!@!.pl&code=634491265 pwd=!!&email=!@!.pl&code=1318026906 pwd=0x0 ... code=367157361 pwd=1&email=1@1.pl&code=363958641 65280 --- pwd=2&email=1@1.pl&code=363893361 65280 pwd=3&email=1@1.pl&code=363828081 65280 pwd=4&email=1@1.pl&code=363762801 65280 pwd=0x0, 0x0.... code=1319091946 pwd=1,0x0 .... code=1315893226 pwd=10&email=1@1.pl&code=1319026666 65280 +++ pwd=11&email=1@1.pl&code=1319091946 65280 pwd=12&email=1@1.pl&code=1319157226 65280 pwd=13&email=1@1.pl&code=1319222506 65280 pwd=14&email=1@1.pl&code=1319287786 ... pwd=110&email=1@1.pl&code=1611736498 65792 --- pwd=111&email=1@1.pl&code=1611670706 64768 pwd=112&email=1@1.pl&code=1611605938 65792 pwd=113&email=1@1.pl&code=1611540146 66816 pwd=114&email=1@1.pl&code=1611473330 pwd=1&email=1@1.pl&code=363958641 16777219 pwd=1&email=2@1.pl&code=380735860 16777215 ?????? pwd=1&email=3@1.pl&code=397513075 16777219 pwd=1&email=4@1.pl&code=414290294 16777215 ?????? pwd=1&email=5@1.pl&code=431067509 pwd=11&email=1@1.pl&code=1319091946 pwd=01&email=1@1.pl&code=1302380266 pwd=10&email=1@1.pl&code=1319026666 pwd=00&email=1@1.pl&code=1302314986 pwd=1&email=0@0.00&code=1869705038 pwd=1&email=0@0.01&code=1886547790 pwd=1&email=0@0.10&code=1852927823 pwd=1&email=0@0.11&code=1869770575 pwd=000&email=1@1.pl&code=1611670963 pwd=100&email=1@1.pl&code=1628448178 pwd=0&email=2@1.pl&code=380801140 pwd=2&email=2@1.pl&code=380670580 pwd=A&email=dupa@jasia.pl&code=1016725374 pwd=B&email=dupa@jasia.pl&code=1016790142 pwd=A&email=0@0.00&code=1870733134 pwd=B&email=0@0.00&code=1870797902 pwd=a&email=0@0.00&code=1872838478 pwd=b&email=0@0.00&code=1872903246 pwd=%3F&email=0@0.00&code=1870618958 pwd=@&email=0@0.00&code=1870667342 pwd=A&email=0@0.00&code=1870733134 ekg-1.9~pre+r2855/dumps/reg-hashes/inst1a000066400000000000000000000165571174410337000201350ustar00rootroot00000000000000 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 39 38 3b 20 44 69 67 45 78 74 29 0d 0a ws 98; DigExt).. 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a 20 Content-Length: 34 38 0d 0a 50 72 61 67 6d 61 3a 20 6e 6f 2d 63 48..Pragma: no-c 61 63 68 65 0d 0a 0d 0a 70 77 64 3d 64 75 70 61 ache....pwd=dupa 31 32 26 65 6d 61 69 6c 3d 77 6f 6a 74 65 6b 6b 12&email=wojtekk 61 40 69 72 63 2e 70 6c 26 63 6f 64 65 3d 31 36 a@irc.pl&code=16 31 34 30 30 30 36 38 31 14000681 21:23:22.340205 217.17.33.22.80 > 10.0.0.3.1051: . ack 273 win 17248 (DF) (ttl 119, id 47717) 45 00 00 28 ba 65 40 00 77 06 45 40 d9 11 21 16 E..(şe@.w.E@Ů.!. 0a 00 00 03 00 50 04 1b 7f 4c 8d c7 00 04 96 cf .....P...L.Ç...Ď 50 10 43 60 bf f7 00 00 P.C`ż÷.. 21:23:22.560188 217.17.33.22.80 > 10.0.0.3.1051: P 1:263(262) ack 273 win 17248 (DF) (ttl 119, id 47824) 45 00 01 2e ba d0 40 00 77 06 43 cf d9 11 21 16 E...şĐ@.w.CĎŮ.!. 0a 00 00 03 00 50 04 1b 7f 4c 8d c7 00 04 96 cf .....P...L.Ç...Ď 50 18 43 60 d4 58 00 00 48 54 54 50 2f 31 2e 31 P.C`ÔX..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 33 34 0 Sep 2001 19:34 3a 35 33 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :53 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 47 SIONIDGGGQQLAG=G 45 4b 44 4e 4a 45 43 50 49 41 43 50 4e 4b 46 4d EKDNJECPIACPNKFM 45 4b 45 4a 4f 46 46 3b 20 70 61 74 68 3d 2f 0d EKEJOFF; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 35 37 34 uccess:1409574 21:23:22.563506 10.0.0.3.1051 > 217.17.33.22.80: F 273:273(0) ack 263 win 8498 (DF) (ttl 32, id 39936) 45 00 00 28 9c 00 40 00 20 06 ba a5 0a 00 00 03 E..(..@. .şĽ.... d9 11 21 16 04 1b 00 50 00 04 96 cf 7f 4c 8e cd Ů.!....P...Ď.L.Í 50 11 21 32 e1 1e 00 00 20 20 20 20 20 20 P.!2á... 21:23:22.570179 217.17.33.22.80 > 10.0.0.3.1051: F 263:263(0) ack 273 win 17248 (DF) (ttl 119, id 47826) 45 00 00 28 ba d2 40 00 77 06 44 d3 d9 11 21 16 E..(şŇ@.w.DÓŮ.!. 0a 00 00 03 00 50 04 1b 7f 4c 8e cd 00 04 96 cf .....P...L.Í...Ď 50 11 43 60 be f0 00 00 P.C`žđ.. 21:23:22.570841 10.0.0.3.1051 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 40192) 45 00 00 28 9d 00 40 00 20 06 b9 a5 0a 00 00 03 E..(..@. .šĽ.... d9 11 21 16 04 1b 00 50 00 04 96 d0 7f 4c 8e ce Ů.!....P...Đ.L.Î 50 10 21 32 e1 1d 00 00 20 20 20 20 20 20 P.!2á... 21:23:22.730189 217.17.33.22.80 > 10.0.0.3.1051: . ack 274 win 17248 (DF) (ttl 119, id 48011) 45 00 00 28 bb 8b 40 00 77 06 44 1a d9 11 21 16 E..(ť.@.w.D.Ů.!. 0a 00 00 03 00 50 04 1b 7f 4c 8e ce 00 04 96 d0 .....P...L.Î...Đ 50 10 43 60 be ef 00 00 P.C`žď.. 21:23:36.213185 10.0.0.3.1053 > 217.17.33.22.80: S 315073:315073(0) win 8192 (DF) (ttl 32, id 40704) 45 00 00 2c 9f 00 40 00 20 06 b7 a1 0a 00 00 03 E..,..@. .ˇĄ.... d9 11 21 16 04 1d 00 50 00 04 ce c1 00 00 00 00 Ů.!....P..ÎÁ.... 60 02 20 00 a0 c9 00 00 02 04 05 b4 20 20 `. ..É.....´ 21:23:36.420175 217.17.33.22.80 > 10.0.0.3.1053: S 2252985549:2252985549(0) ack 315074 win 17520 (DF) (ttl 119, id 58806) 45 00 00 2c e5 b6 40 00 77 06 19 eb d9 11 21 16 E..,ĺś@.w..ëŮ.!. 0a 00 00 03 00 50 04 1d 86 49 d4 cd 00 04 ce c2 .....P...IÔÍ..Π60 12 44 70 21 31 00 00 02 04 05 b4 `.Dp!1.....´ 21:23:36.432988 10.0.0.3.1053 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 40960) 45 00 00 28 a0 00 40 00 20 06 b6 a5 0a 00 00 03 E..(..@. .śĽ.... d9 11 21 16 04 1d 00 50 00 04 ce c2 86 49 d4 ce Ů.!....P..ÎÂ.IÔÎ 50 10 22 38 5b 26 00 00 20 20 20 20 20 20 P."8[&.. 21:23:36.434445 10.0.0.3.1053 > 217.17.33.22.80: P 1:138(137) ack 1 win 8760 (DF) (ttl 32, id 41216) 45 00 00 b1 a1 00 40 00 20 06 b5 1c 0a 00 00 03 E..ąĄ.@. .ľ..... d9 11 21 16 04 1d 00 50 00 04 ce c2 86 49 d4 ce Ů.!....P..ÎÂ.IÔÎ 50 18 22 38 c0 8c 00 00 47 45 54 20 2f 61 70 70 P."8Ŕ...GET /app 73 76 63 2f 61 70 70 6d 73 67 2e 61 73 70 3f 66 svc/appmsg.asp?f 6d 6e 75 6d 62 65 72 3d 37 39 37 30 36 32 20 48 mnumber=797062 H 54 54 50 2f 31 2e 30 0d 0a 48 6f 73 74 3a 20 61 TTP/1.0..Host: a 70 70 6d 73 67 2e 67 61 64 75 2d 67 61 64 75 2e ppmsg.gadu-gadu. 70 6c 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 pl..User-Agent: 4d 6f 7a 69 6c 6c 61 2f 34 2e 37 20 5b 65 6e 5d Mozilla/4.7 [en] 20 28 57 69 6e 39 38 3b 20 49 29 0d 0a 50 72 61 (Win98; I)..Pra 67 6d 61 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d gma: no-cache... 0a . 21:23:36.750192 217.17.33.22.80 > 10.0.0.3.1053: P 1:70(69) ack 138 win 17383 (DF) (ttl 119, id 59029) 45 00 00 6d e6 95 40 00 77 06 18 cb d9 11 21 16 E..mć.@.w..ËŮ.!. 0a 00 00 03 00 50 04 1d 86 49 d4 ce 00 04 cf 4b .....P...IÔÎ..ĎK 50 18 43 e7 f3 f9 00 00 48 54 54 50 2f 31 2e 30 P.Cçóů..HTTP/1.0 20 32 30 30 20 4f 4b 0d 0a 0d 0a 30 20 31 20 30 200 OK....0 1 0 20 32 31 37 2e 31 37 2e 33 33 2e 32 31 3a 38 30 217.17.33.21:80 37 34 20 32 31 37 2e 31 37 2e 33 33 2e 32 31 20 74 217.17.33.21 32 31 37 2e 31 37 2e 33 33 2e 32 31 0a 217.17.33.21. 21:23:36.750294 217.17.33.22.80 > 10.0.0.3.1053: F 70:70(0) ack 138 win 17383 (DF) (ttl 119, id 59030) 45 00 00 28 e6 96 40 00 77 06 19 0f d9 11 21 16 E..(ć.@.w...Ů.!. 0a 00 00 03 00 50 04 1d 86 49 d5 13 00 04 cf 4b .....P...IŐ...ĎK 50 11 43 e7 38 a8 00 00 P.Cç8¨.. 21:23:36.751145 10.0.0.3.1053 > 217.17.33.22.80: . ack 71 win 8691 (DF) (ttl 32, id 41472) 45 00 00 28 a2 00 40 00 20 06 b4 a5 0a 00 00 03 E..(˘.@. .´Ľ.... d9 11 21 16 04 1d 00 50 00 04 cf 4b 86 49 d5 14 Ů.!....P..ĎK.IŐ. 50 10 21 f3 5a 9c 00 00 20 20 20 20 20 20 P.!óZ... 21:23:36.752201 10.0.0.3.1053 > 217.17.33.22.80: F 138:138(0) ack 71 win 8691 (DF) (ttl 32, id 41728) 45 00 00 28 a3 00 40 00 20 06 b3 a5 0a 00 00 03 E..(Ł.@. .łĽ.... d9 11 21 16 04 1d 00 50 00 04 cf 4b 86 49 d5 14 Ů.!....P..ĎK.IŐ. 50 11 21 f3 5a 9b 00 00 20 20 20 20 20 20 P.!óZ... 21:23:36.940197 217.17.33.22.80 > 10.0.0.3.1053: . ack 139 win 17383 (DF) (ttl 119, id 59228) 45 00 00 28 e7 5c 40 00 77 06 18 49 d9 11 21 16 E..(ç\@.w..IŮ.!. 0a 00 00 03 00 50 04 1d 86 49 d5 14 00 04 cf 4c .....P...IŐ...ĎL 50 10 43 e7 38 a7 00 00 P.Cç8§.. ekg-1.9~pre+r2855/dumps/reg-hashes/inst2a000066400000000000000000000120311174410337000201150ustar00rootroot0000000000000021:24:42.796285 10.0.0.3.1056 > 217.17.33.22.80: S 381666:381666(0) win 8192 (DF) (ttl 32, id 44032) 45 00 00 2c ac 00 40 00 20 06 aa a1 0a 00 00 03 E..,Ź.@. .ŞĄ.... d9 11 21 16 04 20 00 50 00 05 d2 e2 00 00 00 00 Ů.!.. .P..Ňâ.... 60 02 20 00 9c a4 00 00 02 04 05 b4 20 20 `. ..¤.....´ 21:24:42.980193 217.17.33.22.80 > 10.0.0.3.1056: S 2745613679:2745613679(0) ack 381667 win 17520 (DF) (ttl 119, id 42923) 45 00 00 2c a7 ab 40 00 77 06 57 f6 d9 11 21 16 E..,§Ť@.w.WöŮ.!. 0a 00 00 03 00 50 04 20 a3 a6 bd 6f 00 05 d2 e3 .....P. ŁŚ˝o..Ňă 60 12 44 70 17 0d 00 00 02 04 05 b4 `.Dp.......´ 21:24:42.980890 10.0.0.3.1056 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 44288) 45 00 00 28 ad 00 40 00 20 06 a9 a5 0a 00 00 03 E..(­.@. .ŠĽ.... d9 11 21 16 04 20 00 50 00 05 d2 e3 a3 a6 bd 70 Ů.!.. .P..Ň㣌˝p 50 10 22 38 51 02 00 00 20 20 20 20 20 20 P."8Q... 21:24:42.982259 10.0.0.3.1056 > 217.17.33.22.80: P 1:265(264) ack 1 win 8760 (DF) (ttl 32, id 44544) 45 00 01 30 ae 00 40 00 20 06 a7 9d 0a 00 00 03 E..0Ž.@. .§..... d9 11 21 16 04 20 00 50 00 05 d2 e3 a3 a6 bd 70 Ů.!.. .P..Ň㣌˝p 50 18 22 38 26 f0 00 00 50 4f 53 54 20 2f 61 70 P."8&đ..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 4e 54 29 0d 0a 43 6f 6e 74 65 6e 74 2d ws NT)..Content- 4c 65 6e 67 74 68 3a 20 34 38 0d 0a 50 72 61 67 Length: 48..Prag 6d 61 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a ma: no-cache.... 70 77 64 3d 64 75 70 61 31 32 33 26 65 6d 61 69 pwd=dupa123&emai 6c 3d 77 6f 6a 74 65 6b 6b 61 40 69 72 63 2e 70 l=wojtekka@irc.p 26 63 6f 64 65 3d 31 35 34 30 39 30 35 34 32 34 &code=1540905424 21:24:43.390206 217.17.33.22.80 > 10.0.0.3.1056: . ack 265 win 17256 (DF) (ttl 119, id 43198) 45 00 00 28 a8 be 40 00 77 06 56 e7 d9 11 21 16 E..(¨ž@.w.VçŮ.!. 0a 00 00 03 00 50 04 20 a3 a6 bd 70 00 05 d3 eb .....P. ŁŚ˝p..Óë 50 10 43 68 2e ca 00 00 P.Ch.Ę.. 21:24:43.840189 217.17.33.22.80 > 10.0.0.3.1056: P 1:263(262) ack 265 win 17256 (DF) (ttl 119, id 43466) 45 00 01 2e a9 ca 40 00 77 06 54 d5 d9 11 21 16 E...ŠĘ@.w.TŐŮ.!. 0a 00 00 03 00 50 04 20 a3 a6 bd 70 00 05 d3 eb .....P. ŁŚ˝p..Óë 50 18 43 68 34 37 00 00 48 54 54 50 2f 31 2e 31 P.Ch47..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 33 36 0 Sep 2001 19:36 3a 31 33 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :13 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 4b SIONIDGGGQQLAG=K 4a 4e 44 4e 4a 45 43 50 4b 41 49 46 44 4d 4f 44 JNDNJECPKAIFDMOD 47 43 4d 49 48 4c 45 3b 20 70 61 74 68 3d 2f 0d GCMIHLE; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 35 38 37 uccess:1409587 21:24:43.842300 10.0.0.3.1056 > 217.17.33.22.80: F 265:265(0) ack 263 win 8498 (DF) (ttl 32, id 44800) 45 00 00 28 af 00 40 00 20 06 a7 a5 0a 00 00 03 E..(Ż.@. .§Ľ.... d9 11 21 16 04 20 00 50 00 05 d3 eb a3 a6 be 76 Ů.!.. .P..Ó료žv 50 11 21 32 4f f9 00 00 20 20 20 20 20 20 P.!2Oů.. 21:24:43.850200 217.17.33.22.80 > 10.0.0.3.1056: F 263:263(0) ack 265 win 17256 (DF) (ttl 119, id 43468) 45 00 00 28 a9 cc 40 00 77 06 55 d9 d9 11 21 16 E..(ŠĚ@.w.UŮŮ.!. 0a 00 00 03 00 50 04 20 a3 a6 be 76 00 05 d3 eb .....P. ŁŚžv..Óë 50 11 43 68 2d c3 00 00 P.Ch-Ă.. 21:24:43.850852 10.0.0.3.1056 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 45056) 45 00 00 28 b0 00 40 00 20 06 a6 a5 0a 00 00 03 E..(°.@. .ŚĽ.... d9 11 21 16 04 20 00 50 00 05 d3 ec a3 a6 be 77 Ů.!.. .P..Ó죌žw 50 10 21 32 4f f8 00 00 20 20 20 20 20 20 P.!2Oř.. 21:24:44.040190 217.17.33.22.80 > 10.0.0.3.1056: . ack 266 win 17256 (DF) (ttl 119, id 43682) 45 00 00 28 aa a2 40 00 77 06 55 03 d9 11 21 16 E..(Ş˘@.w.U.Ů.!. 0a 00 00 03 00 50 04 20 a3 a6 be 77 00 05 d3 ec .....P. ŁŚžw..Óě 50 10 43 68 2d c2 00 00 P.Ch-Â.. ekg-1.9~pre+r2855/dumps/reg-hashes/inst3a000066400000000000000000000132211174410337000201200ustar00rootroot0000000000000021:29:30.112678 10.0.0.3.1081 > 217.17.33.22.80: S 669024:669024(0) win 8192 (DF) (ttl 32, id 11265) 45 00 00 2c 2c 01 40 00 20 06 2a a1 0a 00 00 03 E..,,.@. .*Ą.... d9 11 21 16 04 39 00 50 00 0a 35 60 00 00 00 00 Ů.!..9.P..5`.... 60 02 20 00 3a 09 00 00 02 04 05 b4 20 20 `. .:......´ 21:29:33.394739 10.0.0.3.1081 > 217.17.33.22.80: S 669024:669024(0) win 8192 (DF) (ttl 32, id 11521) 45 00 00 2c 2d 01 40 00 20 06 29 a1 0a 00 00 03 E..,-.@. .)Ą.... d9 11 21 16 04 39 00 50 00 0a 35 60 00 00 00 00 Ů.!..9.P..5`.... 60 02 20 00 3a 09 00 00 02 04 05 b4 20 20 `. .:......´ 21:29:39.391346 217.17.33.22.80 > 10.0.0.3.1081: S 425800492:425800492(0) ack 669025 win 17520 (DF) (ttl 119, id 52785) 45 00 00 2c ce 31 40 00 77 06 31 70 d9 11 21 16 E..,Î1@.w.1pŮ.!. 0a 00 00 03 00 50 04 39 19 61 33 2c 00 0a 35 61 .....P.9.a3,..5a 60 12 44 70 c8 fa 00 00 02 04 05 b4 `.DpČú.....´ 21:29:39.392100 10.0.0.3.1081 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 11777) 45 00 00 28 2e 01 40 00 20 06 28 a5 0a 00 00 03 E..(..@. .(Ľ.... d9 11 21 16 04 39 00 50 00 0a 35 61 19 61 33 2d Ů.!..9.P..5a.a3- 50 10 22 38 02 f0 00 00 20 20 20 20 20 20 P."8.đ.. 21:29:39.393536 10.0.0.3.1081 > 217.17.33.22.80: P 1:258(257) ack 1 win 8760 (DF) (ttl 32, id 12033) 45 00 01 29 2f 01 40 00 20 06 26 a4 0a 00 00 03 E..)/.@. .&¤.... d9 11 21 16 04 39 00 50 00 0a 35 61 19 61 33 2d Ů.!..9.P..5a.a3- 50 18 22 38 c7 dd 00 00 50 4f 53 54 20 2f 61 70 P."8ÇÝ..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 4e 54 3b 20 44 69 67 45 78 74 29 0d 0a ws NT; DigExt).. 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a 20 Content-Length: 33 33 0d 0a 50 72 61 67 6d 61 3a 20 6e 6f 2d 63 33..Pragma: no-c 61 63 68 65 0d 0a 0d 0a 70 77 64 3d 61 26 65 6d ache....pwd=a&em 61 69 6c 3d 61 40 61 2e 70 6c 26 63 6f 64 65 3d ail=a@a.pl&code= 34 35 36 30 36 30 36 30 37 456060607 21:29:44.871426 217.17.33.22.80 > 10.0.0.3.1081: S 425800492:425800492(0) ack 669025 win 17520 (DF) (ttl 119, id 57228) 45 00 00 2c df 8c 40 00 77 06 20 15 d9 11 21 16 E..,ß.@.w. .Ů.!. 0a 00 00 03 00 50 04 39 19 61 33 2c 00 0a 35 61 .....P.9.a3,..5a 60 12 44 70 c8 fa 00 00 02 04 05 b4 `.DpČú.....´ 21:29:44.872064 10.0.0.3.1081 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 12289) 45 00 00 28 30 01 40 00 20 06 26 a5 0a 00 00 03 E..(0.@. .&Ľ.... d9 11 21 16 04 39 00 50 00 0a 36 62 19 61 33 2d Ů.!..9.P..6b.a3- 50 10 22 38 01 ef 00 00 20 20 20 20 20 20 P."8.ď.. 21:29:45.291107 217.17.33.22.80 > 10.0.0.3.1081: . ack 258 win 17263 (DF) (ttl 119, id 57637) 45 00 00 28 e1 25 40 00 77 06 1e 80 d9 11 21 16 E..(á%@.w...Ů.!. 0a 00 00 03 00 50 04 39 19 61 33 2d 00 0a 36 62 .....P.9.a3-..6b 50 10 43 6f e0 b7 00 00 P.Coŕˇ.. 21:29:45.372416 217.17.33.22.80 > 10.0.0.3.1081: P 1:263(262) ack 258 win 17263 (DF) (ttl 119, id 57790) 45 00 01 2e e1 be 40 00 77 06 1c e1 d9 11 21 16 E...áž@.w..áŮ.!. 0a 00 00 03 00 50 04 39 19 61 33 2d 00 0a 36 62 .....P.9.a3-..6b 50 18 43 6f ef 3f 00 00 48 54 54 50 2f 31 2e 31 P.Coď?..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 34 31 0 Sep 2001 19:41 3a 31 30 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :10 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 4c SIONIDGGGQQLAG=L 4e 4a 45 4e 4a 45 43 47 4d 48 4a 41 4a 46 48 43 NJENJECGMHJAJFHC 43 4e 4b 41 42 42 4a 3b 20 70 61 74 68 3d 2f 0d CNKABBJ; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 36 31 39 uccess:1409619 21:29:45.374212 10.0.0.3.1081 > 217.17.33.22.80: F 258:258(0) ack 263 win 8498 (DF) (ttl 32, id 12545) 45 00 00 28 31 01 40 00 20 06 25 a5 0a 00 00 03 E..(1.@. .%Ľ.... d9 11 21 16 04 39 00 50 00 0a 36 62 19 61 34 33 Ů.!..9.P..6b.a43 50 11 21 32 01 ee 00 00 20 20 20 20 20 20 P.!2.î.. 21:29:45.391100 217.17.33.22.80 > 10.0.0.3.1081: F 263:263(0) ack 258 win 17263 (DF) (ttl 119, id 57791) 45 00 00 28 e1 bf 40 00 77 06 1d e6 d9 11 21 16 E..(áż@.w..ćŮ.!. 0a 00 00 03 00 50 04 39 19 61 34 33 00 0a 36 62 .....P.9.a43..6b 50 11 43 6f df b0 00 00 P.Coß°.. 21:29:45.391757 10.0.0.3.1081 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 12801) 45 00 00 28 32 01 40 00 20 06 24 a5 0a 00 00 03 E..(2.@. .$Ľ.... d9 11 21 16 04 39 00 50 00 0a 36 63 19 61 34 34 Ů.!..9.P..6c.a44 50 10 21 32 01 ed 00 00 20 20 20 20 20 20 P.!2.í.. ekg-1.9~pre+r2855/dumps/reg-hashes/inst4a000066400000000000000000000234651174410337000201340ustar00rootroot0000000000000021:31:28.254169 10.0.0.3.1086 > 217.17.33.22.80: S 787183:787183(0) win 8192 (DF) (ttl 32, id 17153) 45 00 00 2c 43 01 40 00 20 06 13 a1 0a 00 00 03 E..,C.@. ..Ą.... d9 11 21 16 04 3e 00 50 00 0c 02 ef 00 00 00 00 Ů.!..>.P...ď.... 60 02 20 00 6c 73 00 00 02 04 05 b4 20 20 `. .ls.....´ 21:31:28.443238 217.17.33.22.80 > 10.0.0.3.1086: S 1243606867:1243606867(0) ack 787184 win 17520 (DF) (ttl 119, id 2979) 45 00 00 2c 0b a3 40 00 77 06 f3 fe d9 11 21 16 E..,.Ł@.w.óţŮ.!. 0a 00 00 03 00 50 04 3e 4a 1f ef 53 00 0c 02 f0 .....P.>J.ďS...đ 60 12 44 70 0e 7f 00 00 02 04 05 b4 `.Dp.......´ 21:31:28.443934 10.0.0.3.1086 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 17409) 45 00 00 28 44 01 40 00 20 06 12 a5 0a 00 00 03 E..(D.@. ..Ľ.... d9 11 21 16 04 3e 00 50 00 0c 02 f0 4a 1f ef 54 Ů.!..>.P...đJ.ďT 50 10 22 38 48 74 00 00 20 20 20 20 20 20 P."8Ht.. 21:31:28.445309 10.0.0.3.1086 > 217.17.33.22.80: P 1:232(231) ack 1 win 8760 (DF) (ttl 32, id 17665) 45 00 01 0f 45 01 40 00 20 06 10 be 0a 00 00 03 E...E.@. ..ž.... d9 11 21 16 04 3e 00 50 00 0c 02 f0 4a 1f ef 54 Ů.!..>.P...đJ.ďT 50 18 22 38 6c c0 00 00 50 4f 53 54 20 2f 61 70 P."8lŔ..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 37 20 5b 65 6e 5d 20 28 57 69 6e 39 38 3b 4.7 [en] (Win98; 20 49 29 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e I)..Content-Len 67 74 68 3a 20 33 34 0d 0a 50 72 61 67 6d 61 3a gth: 34..Pragma: 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a 70 77 64 no-cache....pwd 3d 61 62 26 65 6d 61 69 6c 3d 61 40 61 2e 70 6c =ab&email=a@a.pl 26 63 6f 64 65 3d 37 39 33 38 32 38 36 33 35 &code=793828635 21:31:28.910263 217.17.33.22.80 > 10.0.0.3.1086: . ack 232 win 17289 (DF) (ttl 119, id 3403) 45 00 00 28 0d 4b 40 00 77 06 f2 5a d9 11 21 16 E..(.K@.w.ňZŮ.!. 0a 00 00 03 00 50 04 3e 4a 1f ef 54 00 0c 03 d7 .....P.>J.ďT...× 50 10 43 89 26 3c 00 00 P.C.&<.. 21:31:29.424411 217.17.33.22.80 > 10.0.0.3.1086: P 1:263(262) ack 232 win 17289 (DF) (ttl 119, id 3692) 45 00 01 2e 0e 6c 40 00 77 06 f0 33 d9 11 21 16 E....l@.w.đ3Ů.!. 0a 00 00 03 00 50 04 3e 4a 1f ef 54 00 0c 03 d7 .....P.>J.ďT...× 50 18 43 89 25 a8 00 00 48 54 54 50 2f 31 2e 31 P.C.%¨..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 34 32 0 Sep 2001 19:42 3a 35 38 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :58 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 49 SIONIDGGGQQLAG=I 46 4f 45 4e 4a 45 43 48 48 4e 50 50 41 46 46 48 FOENJECHHNPPAFFH 4a 47 48 42 50 4b 4f 3b 20 70 61 74 68 3d 2f 0d JGHBPKO; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 36 33 30 uccess:1409630 21:31:29.424564 217.17.33.22.80 > 10.0.0.3.1086: F 263:263(0) ack 232 win 17289 (DF) (ttl 119, id 3694) 45 00 00 28 0e 6e 40 00 77 06 f1 37 d9 11 21 16 E..(.n@.w.ń7Ů.!. 0a 00 00 03 00 50 04 3e 4a 1f f0 5a 00 0c 03 d7 .....P.>J.đZ...× 50 11 43 89 25 35 00 00 P.C.%5.. 21:31:29.425685 10.0.0.3.1086 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 17921) 45 00 00 28 46 01 40 00 20 06 10 a5 0a 00 00 03 E..(F.@. ..Ľ.... d9 11 21 16 04 3e 00 50 00 0c 03 d7 4a 1f f0 5b Ů.!..>.P...×J.đ[ 50 10 21 32 47 8c 00 00 20 20 20 20 20 20 P.!2G... 21:31:29.426601 10.0.0.3.1086 > 217.17.33.22.80: F 232:232(0) ack 264 win 8498 (DF) (ttl 32, id 18177) 45 00 00 28 47 01 40 00 20 06 0f a5 0a 00 00 03 E..(G.@. ..Ľ.... d9 11 21 16 04 3e 00 50 00 0c 03 d7 4a 1f f0 5b Ů.!..>.P...×J.đ[ 50 11 21 32 47 8b 00 00 20 20 20 20 20 20 P.!2G... 21:31:29.662445 217.17.33.22.80 > 10.0.0.3.1086: . ack 233 win 17289 (DF) (ttl 119, id 3948) 45 00 00 28 0f 6c 40 00 77 06 f0 39 d9 11 21 16 E..(.l@.w.đ9Ů.!. 0a 00 00 03 00 50 04 3e 4a 1f f0 5b 00 0c 03 d8 .....P.>J.đ[...Ř 50 10 43 89 25 34 00 00 P.C.%4.. 21 7. 17 .3 3. 22 .8 0: S7 87 18 3: 78 71 83 (0 )w in 81 92 ( DF )( tt l3 2, id 17 15 3) !...."......xq.........`.ß........ 45 00 00 2c 43 01 40 00 20 06 13 a1 0a 00 00 03 E..,C.@. ..Ą.... d9 11 21 16 04 3e 00 50 00 0c 02 ef 00 00 00 00 Ů.!..>.P...ď.... 60 02 20 00 6c 73 00 00 02 04 05 b4 20 20 `. .ls.....´ 21:31:28.443238 217.17.33.22.80 > 10.0.0.3.1086: S 1243606867:1243606867(0) ack 787184 win 17520 (DF) (ttl 119, id 2979) 45 00 00 2c 0b a3 40 00 77 06 f3 fe d9 11 21 16 E..,.Ł@.w.óţŮ.!. 0a 00 00 03 00 50 04 3e 4a 1f ef 53 00 0c 02 f0 .....P.>J.ďS...đ 60 12 44 70 0e 7f 00 00 02 04 05 b4 `.Dp.......´ 21:31:28.443934 10.0.0.3.1086 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 17409) 45 00 00 28 44 01 40 00 20 06 12 a5 0a 00 00 03 E..(D.@. ..Ľ.... d9 11 21 16 04 3e 00 50 00 0c 02 f0 4a 1f ef 54 Ů.!..>.P...đJ.ďT 50 10 22 38 48 74 00 00 20 20 20 20 20 20 P."8Ht.. 21:31:28.445309 10.0.0.3.1086 > 217.17.33.22.80: P 1:232(231) ack 1 win 8760 (DF) (ttl 32, id 17665) 45 00 01 0f 45 01 40 00 20 06 10 be 0a 00 00 03 E...E.@. ..ž.... d9 11 21 16 04 3e 00 50 00 0c 02 f0 4a 1f ef 54 Ů.!..>.P...đJ.ďT 50 18 22 38 6c c0 00 00 50 4f 53 54 20 2f 61 70 P."8lŔ..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 37 20 5b 65 6e 5d 20 28 57 69 6e 39 38 3b 4.7 [en] (Win98; 20 49 29 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e I)..Content-Len 67 74 68 3a 20 33 34 0d 0a 50 72 61 67 6d 61 3a gth: 34..Pragma: 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a 70 77 64 no-cache....pwd 3d 61 62 26 65 6d 61 69 6c 3d 61 40 61 2e 70 6c =ab&email=a@a.pl 26 63 6f 64 65 3d 37 39 33 38 32 38 36 33 35 &code=793828635 21:31:28.910263 217.17.33.22.80 > 10.0.0.3.1086: . ack 232 win 17289 (DF) (ttl 119, id 3403) 45 00 00 28 0d 4b 40 00 77 06 f2 5a d9 11 21 16 E..(.K@.w.ňZŮ.!. 0a 00 00 03 00 50 04 3e 4a 1f ef 54 00 0c 03 d7 .....P.>J.ďT...× 50 10 43 89 26 3c 00 00 P.C.&<.. 21:31:29.424411 217.17.33.22.80 > 10.0.0.3.1086: P 1:263(262) ack 232 win 17289 (DF) (ttl 119, id 3692) 45 00 01 2e 0e 6c 40 00 77 06 f0 33 d9 11 21 16 E....l@.w.đ3Ů.!. 0a 00 00 03 00 50 04 3e 4a 1f ef 54 00 0c 03 d7 .....P.>J.ďT...× 50 18 43 89 25 a8 00 00 48 54 54 50 2f 31 2e 31 P.C.%¨..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 34 32 0 Sep 2001 19:42 3a 35 38 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :58 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 49 SIONIDGGGQQLAG=I 46 4f 45 4e 4a 45 43 48 48 4e 50 50 41 46 46 48 FOENJECHHNPPAFFH 4a 47 48 42 50 4b 4f 3b 20 70 61 74 68 3d 2f 0d JGHBPKO; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 36 33 30 uccess:1409630 21:31:29.424564 217.17.33.22.80 > 10.0.0.3.1086: F 263:263(0) ack 232 win 17289 (DF) (ttl 119, id 3694) 45 00 00 28 0e 6e 40 00 77 06 f1 37 d9 11 21 16 E..(.n@.w.ń7Ů.!. 0a 00 00 03 00 50 04 3e 4a 1f f0 5a 00 0c 03 d7 .....P.>J.đZ...× 50 11 43 89 25 35 00 00 P.C.%5.. 21:31:29.425685 10.0.0.3.1086 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 17921) 45 00 00 28 46 01 40 00 20 06 10 a5 0a 00 00 03 E..(F.@. ..Ľ.... d9 11 21 16 04 3e 00 50 00 0c 03 d7 4a 1f f0 5b Ů.!..>.P...×J.đ[ 50 10 21 32 47 8c 00 00 20 20 20 20 20 20 P.!2G... 21:31:29.426601 10.0.0.3.1086 > 217.17.33.22.80: F 232:232(0) ack 264 win 8498 (DF) (ttl 32, id 18177) 45 00 00 28 47 01 40 00 20 06 0f a5 0a 00 00 03 E..(G.@. ..Ľ.... d9 11 21 16 04 3e 00 50 00 0c 03 d7 4a 1f f0 5b Ů.!..>.P...×J.đ[ 50 11 21 32 47 8b 00 00 20 20 20 20 20 20 P.!2G... 21:31:29.662445 217.17.33.22.80 > 10.0.0.3.1086: . ack 233 win 17289 (DF) (ttl 119, id 3948) 45 00 00 28 0f 6c 40 00 77 06 f0 39 d9 11 21 16 E..(.l@.w.đ9Ů.!. 0a 00 00 03 00 50 04 3e 4a 1f f0 5b 00 0c 03 d8 .....P.>J.đ[...Ř 50 10 43 89 25 34 00 00 P.C.%4.. ekg-1.9~pre+r2855/dumps/reg-hashes/inst5a000066400000000000000000000113611174410337000201250ustar00rootroot0000000000000021:33:15.432890 10.0.0.3.1089 > 217.17.33.22.80: S 894377:894377(0) win 8192 (DF) (ttl 32, id 20225) 45 00 00 2c 4f 01 40 00 20 06 07 a1 0a 00 00 03 E..,O.@. ..Ą.... d9 11 21 16 04 41 00 50 00 0d a5 a9 00 00 00 00 Ů.!..A.P..ĽŠ.... 60 02 20 00 c9 b4 00 00 02 04 05 b4 20 20 `. .É´.....´ 21:33:15.682625 217.17.33.22.80 > 10.0.0.3.1089: S 2002635378:2002635378(0) ack 894378 win 17520 (DF) (ttl 119, id 16783) 45 00 00 2c 41 8f 40 00 77 06 be 12 d9 11 21 16 E..,A.@.w.ž.Ů.!. 0a 00 00 03 00 50 04 41 77 5d ca 72 00 0d a5 aa .....P.Aw]Ęr..ĽŞ 60 12 44 70 63 63 00 00 02 04 05 b4 `.Dpcc.....´ 21:33:15.683341 10.0.0.3.1089 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 20481) 45 00 00 28 50 01 40 00 20 06 06 a5 0a 00 00 03 E..(P.@. ..Ľ.... d9 11 21 16 04 41 00 50 00 0d a5 aa 77 5d ca 73 Ů.!..A.P..ĽŞw]Ęs 50 10 22 38 9d 58 00 00 20 20 20 20 20 20 P."8.X.. 21:33:15.684697 10.0.0.3.1089 > 217.17.33.22.80: P 1:256(255) ack 1 win 8760 (DF) (ttl 32, id 20737) 45 00 01 27 51 01 40 00 20 06 04 a6 0a 00 00 03 E..'Q.@. ..Ś.... d9 11 21 16 04 41 00 50 00 0d a5 aa 77 5d ca 73 Ů.!..A.P..ĽŞw]Ęs 50 18 22 38 e5 17 00 00 50 4f 53 54 20 2f 61 70 P."8ĺ...POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 39 38 29 0d 0a 43 6f 6e 74 65 6e 74 2d ws 98)..Content- 4c 65 6e 67 74 68 3a 20 33 39 0d 0a 50 72 61 67 Length: 39..Prag 6d 61 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a ma: no-cache.... 70 77 64 3d 25 32 31 26 65 6d 61 69 6c 3d 25 32 pwd=%21&email=%2 31 40 25 32 31 2e 70 6c 26 63 6f 64 65 3d 36 33 1@%21.pl&code=63 34 34 39 31 32 36 35 4491265 21:33:16.250232 217.17.33.22.80 > 10.0.0.3.1089: P 1:263(262) ack 256 win 17265 (DF) (ttl 119, id 17127) 45 00 01 2e 42 e7 40 00 77 06 bb b8 d9 11 21 16 E...Bç@.w.ť¸Ů.!. 0a 00 00 03 00 50 04 41 77 5d ca 73 00 0d a6 a9 .....P.Aw]Ęs..ŚŠ 50 18 43 71 8b 9a 00 00 48 54 54 50 2f 31 2e 31 P.Cq....HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 34 34 0 Sep 2001 19:44 3a 34 36 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :46 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 41 SIONIDGGGQQLAG=A 49 43 46 4e 4a 45 43 45 42 44 46 4d 45 44 48 4b ICFNJECEBDFMEDHK 4c 4a 48 50 4a 47 49 3b 20 70 61 74 68 3d 2f 0d LJHPJGI; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 36 34 37 uccess:1409647 21:33:16.250383 217.17.33.22.80 > 10.0.0.3.1089: F 263:263(0) ack 256 win 17265 (DF) (ttl 119, id 17128) 45 00 00 28 42 e8 40 00 77 06 bc bd d9 11 21 16 E..(Bč@.w.ź˝Ů.!. 0a 00 00 03 00 50 04 41 77 5d cb 79 00 0d a6 a9 .....P.Aw]Ëy..ŚŠ 50 11 43 71 7a 19 00 00 P.Cqz... 21:33:16.251524 10.0.0.3.1089 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 20993) 45 00 00 28 52 01 40 00 20 06 04 a5 0a 00 00 03 E..(R.@. ..Ľ.... d9 11 21 16 04 41 00 50 00 0d a6 a9 77 5d cb 7a Ů.!..A.P..ŚŠw]Ëz 50 10 21 32 9c 58 00 00 20 20 20 20 20 20 P.!2.X.. 21:33:16.252405 10.0.0.3.1089 > 217.17.33.22.80: F 256:256(0) ack 264 win 8498 (DF) (ttl 32, id 21249) 45 00 00 28 53 01 40 00 20 06 03 a5 0a 00 00 03 E..(S.@. ..Ľ.... d9 11 21 16 04 41 00 50 00 0d a6 a9 77 5d cb 7a Ů.!..A.P..ŚŠw]Ëz 50 11 21 32 9c 57 00 00 20 20 20 20 20 20 P.!2.W.. 21:33:16.470244 217.17.33.22.80 > 10.0.0.3.1089: . ack 257 win 17265 (DF) (ttl 119, id 17408) 45 00 00 28 44 00 40 00 77 06 bb a5 d9 11 21 16 E..(D.@.w.ťĽŮ.!. 0a 00 00 03 00 50 04 41 77 5d cb 7a 00 0d a6 aa .....P.Aw]Ëz..ŚŞ 50 10 43 71 7a 18 00 00 P.Cqz... ekg-1.9~pre+r2855/dumps/reg-hashes/inst6a000066400000000000000000000120241174410337000201230ustar00rootroot0000000000000021:33:55.616925 10.0.0.3.1092 > 217.17.33.22.80: S 934567:934567(0) win 8192 (DF) (ttl 32, id 23553) 45 00 00 2c 5c 01 40 00 20 06 fa a0 0a 00 00 03 E..,\.@. .ú..... d9 11 21 16 04 44 00 50 00 0e 42 a7 00 00 00 00 Ů.!..D.P..B§.... 60 02 20 00 2c b3 00 00 02 04 05 b4 20 20 `. .,ł.....´ 21:33:55.824107 217.17.33.22.80 > 10.0.0.3.1092: S 2289006916:2289006916(0) ack 934568 win 17520 (DF) (ttl 119, id 44869) 45 00 00 2c af 45 40 00 77 06 50 5c d9 11 21 16 E..,ŻE@.w.P\Ů.!. 0a 00 00 03 00 50 04 44 88 6f 79 44 00 0e 42 a8 .....P.D.oyD..B¨ 60 12 44 70 06 7e 00 00 02 04 05 b4 `.Dp.~.....´ 21:33:55.824818 10.0.0.3.1092 > 217.17.33.22.80: . ack 1 win 8760 (DF) (ttl 32, id 23809) 45 00 00 28 5d 01 40 00 20 06 f9 a4 0a 00 00 03 E..(].@. .ů¤.... d9 11 21 16 04 44 00 50 00 0e 42 a8 88 6f 79 45 Ů.!..D.P..B¨.oyE 50 10 22 38 40 73 00 00 20 20 20 20 20 20 P."8@s.. 21:33:55.826220 10.0.0.3.1092 > 217.17.33.22.80: P 1:260(259) ack 1 win 8760 (DF) (ttl 32, id 24065) 45 00 01 2b 5e 01 40 00 20 06 f7 a1 0a 00 00 03 E..+^.@. .÷Ą.... d9 11 21 16 04 44 00 50 00 0e 42 a8 88 6f 79 45 Ů.!..D.P..B¨.oyE 50 18 22 38 23 f2 00 00 50 4f 53 54 20 2f 61 70 P."8#ň..POST /ap 70 73 76 63 2f 66 6d 72 65 67 69 73 74 65 72 2e psvc/fmregister. 61 73 70 20 48 54 54 50 2f 31 2e 30 0d 0a 48 6f asp HTTP/1.0..Ho 73 74 3a 20 72 65 67 69 73 74 65 72 2e 67 61 64 st: register.gad 75 2d 67 61 64 75 2e 70 6c 0d 0a 43 6f 6e 74 65 u-gadu.pl..Conte 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d tion/x-www-form- 75 72 6c 65 6e 63 6f 64 65 64 0d 0a 55 73 65 72 urlencoded..User 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/ 34 2e 30 20 28 63 6f 6d 70 61 74 69 62 6c 65 3b 4.0 (compatible; 20 4d 53 49 45 20 35 2e 30 3b 20 57 69 6e 64 6f MSIE 5.0; Windo 77 73 20 4e 54 29 0d 0a 43 6f 6e 74 65 6e 74 2d ws NT)..Content- 4c 65 6e 67 74 68 3a 20 34 33 0d 0a 50 72 61 67 Length: 43..Prag 6d 61 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 0d 0a ma: no-cache.... 70 77 64 3d 25 32 31 25 32 31 26 65 6d 61 69 6c pwd=%21%21&email 3d 25 32 31 40 25 32 31 2e 50 4c 26 63 6f 64 65 =%21@%21.PL&code 3d 31 33 31 38 30 32 36 39 30 36 =1318026906 21:33:56.290199 217.17.33.22.80 > 10.0.0.3.1092: . ack 260 win 17261 (DF) (ttl 119, id 45203) 45 00 00 28 b0 93 40 00 77 06 4f 12 d9 11 21 16 E..(°.@.w.O.Ů.!. 0a 00 00 03 00 50 04 44 88 6f 79 45 00 0e 43 ab .....P.D.oyE..CŤ 50 10 43 6d 1e 3b 00 00 P.Cm.;.. 21:33:56.530246 217.17.33.22.80 > 10.0.0.3.1092: P 1:263(262) ack 260 win 17261 (DF) (ttl 119, id 45326) 45 00 01 2e b1 0e 40 00 77 06 4d 91 d9 11 21 16 E...ą.@.w.M.Ů.!. 0a 00 00 03 00 50 04 44 88 6f 79 45 00 0e 43 ab .....P.D.oyE..CŤ 50 18 43 6d 16 ac 00 00 48 54 54 50 2f 31 2e 31 P.Cm.Ź..HTTP/1.1 20 32 30 30 20 4f 4b 0d 0a 53 65 72 76 65 72 3a 200 OK..Server: 20 4d 69 63 72 6f 73 6f 66 74 2d 49 49 53 2f 35 Microsoft-IIS/5 2e 30 0d 0a 44 61 74 65 3a 20 4d 6f 6e 2c 20 31 .0..Date: Mon, 1 30 20 53 65 70 20 32 30 30 31 20 31 39 3a 34 35 0 Sep 2001 19:45 3a 32 36 20 47 4d 54 0d 0a 43 6f 6e 6e 65 63 74 :26 GMT..Connect 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a .Content-Length: 20 31 39 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 19..Content-Typ 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 53 65 e: text/html..Se 74 2d 43 6f 6f 6b 69 65 3a 20 41 53 50 53 45 53 t-Cookie: ASPSES 53 49 4f 4e 49 44 47 47 47 51 51 4c 41 47 3d 4f SIONIDGGGQQLAG=O 42 45 46 4e 4a 45 43 4b 48 49 50 45 45 42 47 4a BEFNJECKHIPEEBGJ 50 48 4a 50 4e 47 4e 3b 20 70 61 74 68 3d 2f 0d PHJPNGN; path=/. 0a 43 61 63 68 65 2d 63 6f 6e 74 72 6f 6c 3a 20 .Cache-control: 70 72 69 76 61 74 65 0d 0a 0d 0a 72 65 67 5f 73 private....reg_s 75 63 63 65 73 73 3a 31 34 30 39 36 35 33 uccess:1409653 21:33:56.531968 10.0.0.3.1092 > 217.17.33.22.80: F 260:260(0) ack 263 win 8498 (DF) (ttl 32, id 24321) 45 00 00 28 5f 01 40 00 20 06 f7 a4 0a 00 00 03 E..(_.@. .÷¤.... d9 11 21 16 04 44 00 50 00 0e 43 ab 88 6f 7a 4b Ů.!..D.P..CŤ.ozK 50 11 21 32 3f 6f 00 00 20 20 20 20 20 20 P.!2?o.. 21:33:56.544003 217.17.33.22.80 > 10.0.0.3.1092: F 263:263(0) ack 260 win 17261 (DF) (ttl 119, id 45337) 45 00 00 28 b1 19 40 00 77 06 4e 8c d9 11 21 16 E..(ą.@.w.N.Ů.!. 0a 00 00 03 00 50 04 44 88 6f 7a 4b 00 0e 43 ab .....P.D.ozK..CŤ 50 11 43 6d 1d 34 00 00 P.Cm.4.. 21:33:56.544671 10.0.0.3.1092 > 217.17.33.22.80: . ack 264 win 8498 (DF) (ttl 32, id 24577) 45 00 00 28 60 01 40 00 20 06 f6 a4 0a 00 00 03 E..(`.@. .ö¤.... d9 11 21 16 04 44 00 50 00 0e 43 ac 88 6f 7a 4c Ů.!..D.P..CŹ.ozL 50 10 21 32 3f 6e 00 00 20 20 20 20 20 20 P.!2?n.. 21:33:56.863333 217.17.33.22.80 > 10.0.0.3.1092: . ack 261 win 17261 (DF) (ttl 119, id 45651) 45 00 00 28 b2 53 40 00 77 06 4d 52 d9 11 21 16 E..(˛S@.w.MRŮ.!. 0a 00 00 03 00 50 04 44 88 6f 7a 4c 00 0e 43 ac .....P.D.ozL..CŹ 50 10 43 6d 1d 33 00 00 P.Cm.3.. ekg-1.9~pre+r2855/dumps/search50.txt000066400000000000000000000311121174410337000171200ustar00rootroot0000000000000015:14:53.402791 192.168.110.128.1027 > 217.17.41.89.8074: P [tcp sum ok] 202036:202065(29) ack 2483772057 win 8265 (DF) (ttl 128, id 12032, len 69) 0x0020 1400 0000 1500 0000 ........ 0x0030 03c1 a91f 3e66 6d6e 756d 6265 7200 3533 ....>fmnumber.53 0x0040 3533 3333 00 5333. 15:14:53.780194 217.17.41.89.8074 > 192.168.110.128.1027: . [tcp sum ok] 1:124(123) ack 29 win 65280 (ttl 128, id 65275, len 163) 0x0020 0e00 0000 7300 0000 ....s... 0x0030 05c1 a91f 3e46 6d4e 756d 6265 7200 3533 ....>FmNumber.53 0x0040 3533 3333 0046 6d53 7461 7475 7300 3100 5333.FmStatus.1. 0x0050 6669 7273 746e 616d 6500 576f 6a74 656b firstname.Wojtek 0x0060 006e 6963 6b6e 616d 6500 776f 6a74 656b .nickname.wojtek 0x0070 6b61 0062 6972 7468 7965 6172 0031 3938 ka.birthyear.198 0x0080 3100 6369 7479 0042 7964 676f 737a 637a 1.city.Bydgoszcz 0x0090 0000 6e65 7874 7374 6172 7400 3533 3533 ..nextstart.5353 0x00a0 3333 00 33. // płeć: mężczyzna 15:19:29.983170 192.168.110.128.1027 > 217.17.41.89.8074: P [tcp sum ok] 82:198(116) ack 247 win 8576 (DF) (ttl 128, id 13568, len 156) 0x0020 1400 0000 6c00 0000 ....l... 0x0030 03d4 aa1f 3e66 6972 7374 6e61 6d65 0069 ....>firstname.i 0x0040 6d69 ea00 6c61 7374 6e61 6d65 006e 617a mi..lastname.naz 0x0050 7769 736b 6f00 6e69 636b 6e61 6d65 0070 wisko.nickname.p 0x0060 7365 7564 6f00 6369 7479 006d 6961 7374 seudo.city.miast 0x0070 6f00 6765 6e64 6572 0032 0062 6972 7468 o.gender.2.birth 0x0080 7965 6172 0031 3936 3920 3139 3931 0066 year.1969.1991.f 0x0090 6d6e 756d 6265 7200 3132 3300 mnumber.123. 15:19:41.980202 217.17.41.89.8074 > 192.168.110.128.1027: . [tcp sum ok] 247:297(50) ack 198 win 65280 (ttl 128, id 65283, len 90) 0x0020 0e00 0000 2a00 0000 ....*... 0x0030 05d4 aa1f 3e46 6d4e 756d 6265 7200 3132 ....>FmNumber.12 0x0040 3300 466d 5374 6174 7573 0031 0000 6e65 3.FmStatus.1..ne 0x0050 7874 7374 6172 7400 3000 xtstart.0. // płeć kobieta, tylko aktywni 15:21:18.795922 192.168.110.128.1027 > 217.17.41.89.8074: P [tcp sum ok] 198:327(129) ack 297 win 8526 (DF) (ttl 128, id 14080, len 169) 0x0020 1400 0000 7900 0000 ....y... 0x0030 0341 ab1f 3e66 6972 7374 6e61 6d65 0069 .A..>firstname.i 0x0040 6d69 ea00 6c61 7374 6e61 6d65 006e 617a mi..lastname.naz 0x0050 7769 736b 6f00 6e69 636b 6e61 6d65 0070 wisko.nickname.p 0x0060 7365 7564 6f00 6369 7479 006d 6961 7374 seudo.city.miast 0x0070 6f00 6765 6e64 6572 0031 0062 6972 7468 o.gender.1.birth 0x0080 7965 6172 0031 3936 3920 3139 3931 0066 year.1969.1991.f 0x0090 6d6e 756d 6265 7200 3132 3300 4163 7469 mnumber.123.Acti 0x00a0 7665 4f6e 6c79 0031 00 veOnly.1. 15:21:19.610091 217.17.41.89.8074 > 192.168.110.128.1027: . [tcp sum ok] 297:347(50) ack 327 win 65280 (ttl 128, id 65287, len 90) 0x0020 0e00 0000 2a00 0000 ....*... 0x0030 0541 ab1f 3e46 6d4e 756d 6265 7200 3132 .A..>FmNumber.12 0x0040 3300 466d 5374 6174 7573 0031 0000 6e65 3.FmStatus.1..ne 0x0050 7874 7374 6172 7400 3000 xtstart.0. 15:24:10.008779 192.168.110.128.1027 > 217.17.41.89.8074: P [tcp sum ok] 385:430(45) ack 593 win 8230 (DF) (ttl 128, id 15616, len 85) 0x0020 1400 0000 2500 0000 ....%... 0x0030 03ec ab1f 3e66 6972 7374 6e61 6d65 0077 ....>firstname.w 0x0040 6f6a 7465 6b00 6369 7479 0062 7964 676f ojtek.city.bydgo 0x0050 737a 637a 00 szcz. 15:24:10.908917 217.17.41.89.8074 > 192.168.110.128.1027: . 593:2041(1448) ack 430 win 65280 (ttl 128, id 65295, len 1488) 0x0020 0e00 0000 e806 0000 ........ 0x0030 05ec ab1f 3e46 6d4e 756d 6265 7200 3237 ....>FmNumber.27 0x0040 3730 3700 466d 5374 6174 7573 0031 0066 707.FmStatus.1.f 0x0050 6972 7374 6e61 6d65 0057 6f6a 7465 6b00 irstname.Wojtek. 0x0060 6e69 636b 6e61 6d65 0057 6f57 0062 6972 nickname.WoW.bir 0x0070 7468 7965 6172 0031 3937 3900 6369 7479 thyear.1979.city 0x0080 0042 7964 676f 737a 637a 0000 466d 4e75 .Bydgoszcz..FmNu 0x0090 6d62 6572 0033 3736 3630 0046 6d53 7461 mber.37660.FmSta 0x00a0 7475 7300 3100 6669 7273 746e 616d 6500 tus.1.firstname. 0x00b0 576f 6a74 656b 006e 6963 6b6e 616d 6500 Wojtek.nickname. 0x00c0 566f 7953 0062 6972 7468 7965 6172 0030 VoyS.birthyear.0 0x00d0 0063 6974 7900 4279 6467 6f73 7a63 7a00 .city.Bydgoszcz. 0x00e0 0046 6d4e 756d 6265 7200 3232 3337 3232 .FmNumber.223722 0x00f0 3000 466d 5374 6174 7573 0031 0066 6972 0.FmStatus.1.fir 0x0100 7374 6e61 6d65 0057 6f6a 7465 6b00 6e69 stname.Wojtek.ni 0x0110 636b 6e61 6d65 0042 6967 6f73 0062 6972 ckname.Bigos.bir 0x0120 7468 7965 6172 0031 3938 3500 6369 7479 thyear.1985.city 0x0130 0042 7964 676f 737a 637a 0000 466d 4e75 .Bydgoszcz..FmNu 0x0140 6d62 6572 0032 3234 3432 3139 0046 6d53 mber.2244219.FmS 0x0150 7461 7475 7300 3100 6669 7273 746e 616d tatus.1.firstnam 0x0160 6500 576f 6a74 656b 006e 6963 6b6e 616d e.Wojtek.nicknam 0x0170 6500 776f 6a74 6173 7300 6269 7274 6879 e.wojtass.birthy 0x0180 6561 7200 3139 3837 0063 6974 7900 4279 ear.1987.city.By 0x0190 6467 6f73 7a63 7a00 0046 6d4e 756d 6265 dgoszcz..FmNumbe 0x01a0 7200 3232 3436 3237 3100 466d 5374 6174 r.2246271.FmStat 0x01b0 7573 0031 0066 6972 7374 6e61 6d65 0077 us.1.firstname.w 0x01c0 6f6a 7465 6b00 6e69 636b 6e61 6d65 0061 ojtek.nickname.a 0x01d0 6972 626f 7900 6269 7274 6879 6561 7200 irboy.birthyear. 0x01e0 3139 3838 0063 6974 7900 6279 6467 6f73 1988.city.bydgos 0x01f0 7a63 7a00 0046 6d4e 756d 6265 7200 3232 zcz..FmNumber.22 0x0200 3438 3135 3100 466d 5374 6174 7573 0032 48151.FmStatus.2 0x0210 0066 6972 7374 6e61 6d65 0057 6f6a 7465 .firstname.Wojte 0x0220 6b00 6e69 636b 6e61 6d65 002d 2d2d 3a3a k.nickname.---:: 0x0230 4275 726e 6148 3a3a 2d2d 2d00 6269 7274 BurnaH::---.birt 0x0240 6879 6561 7200 3139 3833 0063 6974 7900 hyear.1983.city. 0x0250 4279 6467 6f73 7a63 7a00 0046 6d4e 756d Bydgoszcz..FmNum 0x0260 6265 7200 3232 3439 3436 3100 466d 5374 ber.2249461.FmSt 0x0270 6174 7573 0031 0066 6972 7374 6e61 6d65 atus.1.firstname 0x0280 0077 6f6a 7465 6b00 6e69 636b 6e61 6d65 .wojtek.nickname 0x0290 0062 6172 616e 0062 6972 7468 7965 6172 .baran.birthyear 0x02a0 0031 3938 3600 6369 7479 0062 7964 676f .1986.city.bydgo 0x02b0 737a 637a 0000 466d 4e75 6d62 6572 0032 szcz..FmNumber.2 0x02c0 3236 3139 3234 0046 6d53 7461 7475 7300 261924.FmStatus. 0x02d0 3100 6669 7273 746e 616d 6500 576f 6a74 1.firstname.Wojt 0x02e0 656b 0062 6972 7468 7965 6172 0030 0063 ek.birthyear.0.c 0x02f0 6974 7900 4279 6467 6f73 7a63 7a00 0046 ity.Bydgoszcz..F 0x0300 6d4e 756d 6265 7200 3232 3832 3033 3800 mNumber.2282038. 0x0310 466d 5374 6174 7573 0031 0066 6972 7374 FmStatus.1.first 0x0320 6e61 6d65 0077 6f6a 7465 6b00 6e69 636b name.wojtek.nick 0x0330 6e61 6d65 0057 4f4a 5441 5300 6269 7274 name.WOJTAS.birt 0x0340 6879 6561 7200 3139 3830 0063 6974 7900 hyear.1980.city. 0x0350 6279 6467 6f73 7a63 7a00 0046 6d4e 756d bydgoszcz..FmNum 0x0360 6265 7200 3232 3936 3632 3900 466d 5374 ber.2296629.FmSt 0x0370 6174 7573 0031 0066 6972 7374 6e61 6d65 atus.1.firstname 0x0380 0077 6f6a 7465 6b00 6e69 636b 6e61 6d65 .wojtek.nickname 0x0390 0064 0062 6972 7468 7965 6172 0031 3937 .d.birthyear.197 0x03a0 3300 6369 7479 0042 7964 676f 737a 637a 3.city.Bydgoszcz 0x03b0 0000 466d 4e75 6d62 6572 0032 3239 3933 ..FmNumber.22993 0x03c0 3738 0046 6d53 7461 7475 7300 3500 6669 78.FmStatus.5.fi 0x03d0 7273 746e 616d 6500 576f 6a74 656b 006e rstname.Wojtek.n 0x03e0 6963 6b6e 616d 6500 766f 7974 6563 0062 ickname.voytec.b 0x03f0 6972 7468 7965 6172 0031 3938 3400 6369 irthyear.1984.ci 0x0400 7479 0062 7964 676f 737a 637a 0000 466d ty.bydgoszcz..Fm 0x0410 4e75 6d62 6572 0032 3331 3233 3938 0046 Number.2312398.F 0x0420 6d53 7461 7475 7300 3100 6669 7273 746e mStatus.1.firstn 0x0430 616d 6500 776f 6a74 656b 006e 6963 6b6e ame.wojtek.nickn 0x0440 616d 6500 6269 676f 7300 6269 7274 6879 ame.bigos.birthy 0x0450 6561 7200 3139 3835 0063 6974 7900 4279 ear.1985.city.By 0x0460 6467 6f73 7a63 7a00 0046 6d4e 756d 6265 dgoszcz..FmNumbe 0x0470 7200 3233 3137 3232 3500 466d 5374 6174 r.2317225.FmStat 0x0480 7573 0031 0066 6972 7374 6e61 6d65 0057 us.1.firstname.W 0x0490 6f6a 7465 6b00 6269 7274 6879 6561 7200 ojtek.birthyear. 0x04a0 3139 3637 0063 6974 7900 4279 6467 6f73 1967.city.Bydgos 0x04b0 7a63 7a00 0046 6d4e 756d 6265 7200 3233 zcz..FmNumber.23 0x04c0 3437 3138 3900 466d 5374 6174 7573 0031 47189.FmStatus.1 0x04d0 0066 6972 7374 6e61 6d65 0057 6f6a 7465 .firstname.Wojte 0x04e0 6b00 6e69 636b 6e61 6d65 0047 6f6b 7500 k.nickname.Goku. 0x04f0 6369 7479 0042 7964 676f 737a 637a 0000 city.Bydgoszcz.. 0x0500 466d 4e75 6d62 6572 0032 3335 3236 3436 FmNumber.2352646 0x0510 0046 6d53 7461 7475 7300 3100 6669 7273 .FmStatus.1.firs 0x0520 746e 616d 6500 576f 6a74 656b 006e 6963 tname.Wojtek.nic 0x0530 6b6e 616d 6500 536b 6f63 7a65 6b00 6269 kname.Skoczek.bi 0x0540 7274 6879 6561 7200 3139 3639 0063 6974 rthyear.1969.cit 0x0550 7900 4279 6467 6f73 7a63 7a00 0046 6d4e y.Bydgoszcz..FmN 0x0560 756d 6265 7200 3233 3635 3332 3500 466d umber.2365325.Fm 0x0570 5374 6174 7573 0031 0066 6972 7374 6e61 Status.1.firstna 0x0580 6d65 0077 6f6a 7465 6b00 6269 7274 6879 me.wojtek.birthy 0x0590 6561 7200 3139 3734 0063 6974 7900 6279 ear.1974.city.by 0x05a0 6467 6f73 7a63 7a00 0046 6d4e 756d 6265 dgoszcz..FmNumbe 0x05b0 7200 3233 3733 3132 3700 466d 5374 6174 r.2373127.FmStat 0x05c0 7573 0031 0066 6972 7374 6e61 6d65 us.1.firstname 15:24:10.920205 217.17.41.89.8074 > 192.168.110.128.1027: . [tcp sum ok] 2041:2369(328) ack 430 win 65280 (ttl 128, id 65296, len 368) 0x0020 6f6a 7465 6b00 6e69 ojtek.ni 0x0030 636b 6e61 6d65 0057 6f6a 0062 6972 7468 ckname.Woj.birth 0x0040 7965 6172 0031 3935 3500 6369 7479 0042 year.1955.city.B 0x0050 7964 676f 737a 637a 0000 466d 4e75 6d62 ydgoszcz..FmNumb 0x0060 6572 0032 3338 3532 3630 0046 6d53 7461 er.2385260.FmSta 0x0070 7475 7300 3100 6669 7273 746e 616d 6500 tus.1.firstname. 0x0080 576f 6a74 656b 006e 6963 6b6e 616d 6500 Wojtek.nickname. 0x0090 4a65 6c65 6e00 6269 7274 6879 6561 7200 Jelen.birthyear. 0x00a0 3139 3838 0063 6974 7900 4279 6467 6f73 1988.city.Bydgos 0x00b0 7a63 7a00 0046 6d4e 756d 6265 7200 3234 zcz..FmNumber.24 0x00c0 3130 3539 3000 466d 5374 6174 7573 0031 10590.FmStatus.1 0x00d0 0066 6972 7374 6e61 6d65 0077 6f6a 7465 .firstname.wojte 0x00e0 6b00 6e69 636b 6e61 6d65 0070 7461 737a k.nickname.ptasz 0x00f0 656b 0062 6972 7468 7965 6172 0031 3938 ek.birthyear.198 0x0100 3000 6369 7479 0062 7964 676f 737a 637a 0.city.bydgoszcz 0x0110 0000 466d 4e75 6d62 6572 0032 3431 3539 ..FmNumber.24159 0x0120 3937 0046 6d53 7461 7475 7300 3100 6669 97.FmStatus.1.fi 0x0130 7273 746e 616d 6500 776f 6a74 656b 0062 rstname.wojtek.b 0x0140 6972 7468 7965 6172 0031 3936 3200 6369 irthyear.1962.ci 0x0150 7479 0042 7964 676f 737a 637a 0000 6e65 ty.Bydgoszcz..ne 0x0160 7874 7374 6172 7400 3234 3135 3939 3700 xtstart.2415997. // więcej... 15:26:29.806266 192.168.110.128.1027 > 217.17.41.89.8074: P [tcp sum ok] 454:515(61) ack 2369 win 8576 (DF) (ttl 128, id 16640, len 101) 0x0020 1400 0000 3500 0000 ....5... 0x0030 037a ac1f 3e66 6972 7374 6e61 6d65 0077 .z..>firstname.w 0x0040 6f6a 7465 6b00 6369 7479 0062 7964 676f ojtek.city.bydgo 0x0050 737a 637a 0066 6d73 7461 7274 0032 3431 szcz.fmstart.241 0x0060 3539 3937 00 5997. ekg-1.9~pre+r2855/examples/000077500000000000000000000000001174410337000154355ustar00rootroot00000000000000ekg-1.9~pre+r2855/examples/.cvsignore000066400000000000000000000001621174410337000174340ustar00rootroot00000000000000Makefile send search-sync search-async register-sync register-async remind-sync remind-async conn-async httphash ekg-1.9~pre+r2855/examples/Makefile.in000066400000000000000000000020011174410337000174730ustar00rootroot00000000000000# $Id$ CC = @CC@ CFLAGS = @CFLAGS_LIBGADU@ @CFLAGS@ -I.. -I../lib -I../src LIBS = @LIBS_LIBGADU@ MAKE = @MAKE@ OBJS = ../lib/libgadu.a all: register-sync register-async conn-async send remind-async remind-sync httphash register-sync: register.c $(OBJS) $(CC) $(CFLAGS) register.c -o register-sync $(OBJS) $(LIBS) register-async: register.c $(OBJS) $(CC) $(CFLAGS) register.c -o register-async -DASYNC $(OBJS) $(LIBS) remind-sync: remind.c $(OBJS) $(CC) $(CFLAGS) remind.c -o remind-sync $(OBJS) $(LIBS) remind-async: remind.c $(OBJS) $(CC) $(CFLAGS) remind.c -o remind-async -DASYNC $(OBJS) $(LIBS) send: send.c $(OBJS) $(CC) $(CFLAGS) send.c -o send $(OBJS) $(LIBS) httphash: httphash.c $(OBJS) $(CC) $(CFLAGS) httphash.c -o httphash $(OBJS) $(LIBS) conn-async: conn-async.c $(OBJS) $(CC) $(CFLAGS) conn-async.c -o conn-async $(OBJS) $(LIBS) $(OBJS): cd ../lib && $(MAKE) # clean: rm -f *~ *.o send conn-async register-{sync,async} remind-{sync,async} httphash distclean: clean rm -f Makefile ekg-1.9~pre+r2855/examples/conn-async.c000066400000000000000000000027141174410337000176550ustar00rootroot00000000000000/* $Id$ */ /* * głupiutki przykład, jak się połączyć, korzystając z asynchronicznych * socketów. nic poza połączeniem nie robi. nie przejmuje się błędami. */ #include #include #include #include #include #include #include #include "libgadu.h" int main() { struct gg_login_params p; struct gg_session *sess; struct timeval tv; struct gg_event *e; fd_set rd, wd; int ret; gg_debug_level = ~0; memset(&p, 0, sizeof(p)); p.uin = 123456; p.password = "dupa.8"; p.async = 1; sess = gg_login(&p); for (;;) { FD_ZERO(&rd); FD_ZERO(&wd); if ((sess->check & GG_CHECK_READ)) FD_SET(sess->fd, &rd); if ((sess->check & GG_CHECK_WRITE)) FD_SET(sess->fd, &wd); tv.tv_sec = 10; tv.tv_usec = 0; ret = select(sess->fd + 1, &rd, &wd, NULL, &tv); if (!ret) { printf("timeout! wypad!\n"); return 1; } else { if (sess && (FD_ISSET(sess->fd, &rd) || FD_ISSET(sess->fd, &wd))) { if (!(e = gg_watch_fd(sess))) { printf("zerfauo pouontshenie!\n"); return 1; } if (e->type == GG_EVENT_CONN_SUCCESS) { printf("połączyłem się\n"); gg_free_event(e); gg_logoff(sess); gg_free_session(sess); return 1; } if (e->type == GG_EVENT_CONN_FAILED) { printf("errrror\n"); gg_free_event(e); gg_logoff(sess); gg_free_session(sess); return 1; } gg_free_event(e); } } } return -1; } ekg-1.9~pre+r2855/examples/httphash.c000066400000000000000000000026241174410337000174300ustar00rootroot00000000000000#include #include #include #include "libgadu.h" int main(int argc, char **argv) { char buf[100]; int i; if (argc > 2 && !strcmp(argv[1], "-b")) { int count = argc - 3; uint32_t val = atoi(argv[2]); for (i = 0; i < (1 << count); i++) { char *args[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; uint32_t res; int c = 0, j; if (i & 1) args[c++] = argv[3]; if (i & 2) args[c++] = argv[4]; if (i & 4) args[c++] = argv[5]; if (i & 8) args[c++] = argv[6]; if (i & 16) args[c++] = argv[7]; if (i & 32) args[c++] = argv[8]; if (i & 64) args[c++] = argv[9]; if (i & 128) args[c++] = argv[10]; strcpy(buf, ""); for (j = 0; j < c; j++) strcat(buf, "s"); res = gg_http_hash(buf, args[0], args[1], args[2], args[3], args[4], args[5], args[6], NULL); printf("%s %s %s %s %s %s %s %s", buf, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); if (res == val) printf(" MATCH!\n"); else printf("\n"); } return 0; } if (argc < 2 || argc > 10) { fprintf(stderr, "użycie: %s [wyrazy] [do] [hasha]\n", argv[0]); return 1; } strcpy(buf, ""); for (i = 1; i < argc; i++) strcat(buf, "s"); printf("%s\n", buf); printf("%u\n", gg_http_hash(buf, argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10])); return 0; } ekg-1.9~pre+r2855/examples/register.c000066400000000000000000000036071174410337000174330ustar00rootroot00000000000000/* $Id$ */ #include #include "libgadu.h" #ifdef ASYNC #include #include #include #include void sigchld() { wait(NULL); signal(SIGCHLD, sigchld); } #endif int main() { struct gg_http *h; struct gg_pubdir *p; char email[100], password[100]; gg_debug_level = 255; printf("e-mail: "); fgets(email, 99, stdin); if (email[strlen(email)-1] == '\n') email[strlen(email)-1] = 0; printf("password: "); fgets(password, 99, stdin); if (password[strlen(password)-1] == '\n') password[strlen(password)-1] = 0; #ifndef ASYNC if (!(h = gg_register(email, password, 0))) { printf("błąd\n"); return 1; } p = h->data; printf("success=%d, uin=%ld\n", p->success, p->uin); gg_free_register(h); #else signal(SIGCHLD, sigchld); if (!(h = gg_register(email, password, 1))) return 1; while (1) { fd_set rd, wr, ex; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); if ((h->check & GG_CHECK_READ)) FD_SET(h->fd, &rd); if ((h->check & GG_CHECK_WRITE)) FD_SET(h->fd, &wr); FD_SET(h->fd, &ex); if (select(h->fd + 1, &rd, &wr, &ex, NULL) == -1 || FD_ISSET(h->fd, &ex)) { if (errno == EINTR) continue; gg_free_register(h); perror("select"); return 1; } if (FD_ISSET(h->fd, &rd) || FD_ISSET(h->fd, &wr)) { if (gg_register_watch_fd(h) == -1) { gg_free_register(h); fprintf(stderr, "no błąd jak błąd\n"); return 1; } if (h->state == GG_STATE_ERROR) { gg_free_register(h); fprintf(stderr, "jakiśtam błąd\n"); return 1; } if (h->state == GG_STATE_DONE) { p = h->data; printf("success=%d, uin=%ld\n", p->success, p->uin); gg_free_register(h); break; } } } #endif return 0; } ekg-1.9~pre+r2855/examples/remind.c000066400000000000000000000032221174410337000170560ustar00rootroot00000000000000/* $Id$ */ #include #include "libgadu.h" #ifdef ASYNC #include #include #include #include void sigchld() { wait(NULL); signal(SIGCHLD, sigchld); } #endif int main() { struct gg_http *h; struct gg_pubdir *p; uin_t uin; gg_debug_level = 255; printf("uin: "); scanf("%ld", &uin); #ifndef ASYNC if (!(h = gg_remind_passwd(uin, 0))) { printf("błąd\n"); return 1; } p = h->data; printf("success=%d\n", p->success); gg_free_remind_passwd(h); #else signal(SIGCHLD, sigchld); if (!(h = gg_remind_passwd(uin, 1))) return 1; while (1) { fd_set rd, wr, ex; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); if ((h->check & GG_CHECK_READ)) FD_SET(h->fd, &rd); if ((h->check & GG_CHECK_WRITE)) FD_SET(h->fd, &wr); FD_SET(h->fd, &ex); if (select(h->fd + 1, &rd, &wr, &ex, NULL) == -1 || FD_ISSET(h->fd, &ex)) { if (errno == EINTR) continue; gg_free_remind_passwd(h); perror("select"); return 1; } if (FD_ISSET(h->fd, &rd) || FD_ISSET(h->fd, &wr)) { if (gg_remind_passwd_watch_fd(h) == -1) { gg_free_remind_passwd(h); fprintf(stderr, "no błąd jak błąd\n"); return 1; } if (h->state == GG_STATE_ERROR) { gg_free_remind_passwd(h); fprintf(stderr, "jakiśtam błąd\n"); return 1; } if (h->state == GG_STATE_DONE) { p = h->data; printf("success=%d\n", p->success); gg_free_remind_passwd(h); break; } } } #endif return 0; } ekg-1.9~pre+r2855/examples/send.c000066400000000000000000000023661174410337000165410ustar00rootroot00000000000000/* * przykład prostego programu łączącego się z serwerem i wysyłającego * jedną wiadomość. */ #include #include #include #include #include "libgadu.h" int main(int argc, char **argv) { struct gg_session *sess; struct gg_event *e; struct gg_login_params p; if (argc < 5) { fprintf(stderr, "użycie: %s \n", argv[0]); return 1; } gg_debug_level = 255; memset(&p, 0, sizeof(p)); p.uin = atoi(argv[2]); p.password = argv[1]; if (!(sess = gg_login(&p))) { printf("Nie udało się połączyć: %s\n", strerror(errno)); gg_free_session(sess); return 1; } printf("Połączono.\n"); if (gg_send_message(sess, GG_CLASS_MSG, atoi(argv[3]), argv[4]) == -1) { printf("Połączenie przerwane: %s\n", strerror(errno)); gg_free_session(sess); return 1; } /* poniższą część można olać, ale poczekajmy na potwierdzenie */ while (0) { if (!(e = gg_watch_fd(sess))) { printf("Połączenie przerwane: %s\n", strerror(errno)); gg_logoff(sess); gg_free_session(sess); return 1; } if (e->type == GG_EVENT_ACK) { printf("Wysłano.\n"); gg_free_event(e); break; } gg_free_event(e); } gg_logoff(sess); gg_free_session(sess); return 0; } ekg-1.9~pre+r2855/install-sh000077500000000000000000000127201174410337000156250ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 ekg-1.9~pre+r2855/m4/000077500000000000000000000000001174410337000141375ustar00rootroot00000000000000ekg-1.9~pre+r2855/m4/Makefile000066400000000000000000000000411174410337000155720ustar00rootroot00000000000000default: cd .. && ./autogen.sh ekg-1.9~pre+r2855/m4/curses.m4000066400000000000000000000037161174410337000157140ustar00rootroot00000000000000dnl Rewritten from scratch. --wojtekka dnl $Id$ AC_DEFUN([AC_CHECK_NCURSES], [ AC_SUBST(CURSES_LIBS) AC_SUBST(CURSES_INCLUDES) AC_ARG_WITH(ncurses, [[ --with-ncurses[=dir] Compile with ncurses/locate base dir]], [ if test "x$withval" = "xno" ; then without_ncurses=yes with_arg="" elif test "x$withval" != "xyes" ; then with_arg=$withval/include:-L$withval/lib fi ]) if test "x$without_ncurses" != "xyes" ; then for i in $with_arg \ : \ -I/usr/pkg/include:-L/usr/pkg/lib \ -I/usr/contrib/include:-L/usr/contrib/lib \ -I/usr/freeware/include:-L/usr/freeware/lib32 \ -I/sw/include:-L/sw/lib \ -I/cw/include:-L/cw/lib \ -I/boot/home/config/include:-L/boot/home/config/lib; do incl=`echo "$i" | sed 's/:.*//'` # 'głupi vim lib=`echo "$i" | sed 's/.*://'` # 'głupi vim path=`echo "$incl" | sed 's/^..//'` # 'głupi vim cppflags="$CPPFLAGS" ldflags="$LDFLAGS" CPPFLAGS="$CPPFLAGS $incl" LDFLAGS="$LDFLAGS $libs" have_ncurses_h="" if test "x$path" = "x" -o -f "$path/ncurses.h" -o -f "$path/ncurses/ncurses.h"; then $as_unset ac_cv_header_ncurses_h $as_unset ac_cv_header_ncurses_ncurses_h AC_CHECK_HEADERS([ncurses.h], [ CURSES_INCLUDES="$incl" have_ncurses_h=yes ], [ AC_CHECK_HEADERS([ncurses/ncurses.h], [ CURSES_INCLUDES="$incl" have_ncurses_h=yes ]) ]) fi if test "x$have_ncurses_h" = "xyes"; then $as_unset ac_cv_lib_ncurses_initscr $as_unset ac_cv_lib_curses_initscr have_libncurses="" AC_CHECK_LIB(ncurses, initscr, [ CURSES_LIBS="$libs -lncurses" have_libncurses=yes ], [ AC_CHECK_LIB(curses, initscr, [ CURSES_LIBS="$libs -lcurses" have_libncurses=yes ]) ]) if test "x$have_libncurses" = "xyes"; then AC_DEFINE(HAVE_NCURSES, 1, [define if ncurses is installed]) have_ncurses=yes break fi fi CPPFLAGS="$cppflags" LDFLAGS="$ldflags" done fi ]) ekg-1.9~pre+r2855/m4/gtk2.m4000066400000000000000000000164231174410337000152560ustar00rootroot00000000000000# Configure paths for GTK+ # Owen Taylor 1997-2001 dnl AC_CHECK_GTK_2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES, dnl pass to pkg-config dnl AC_DEFUN([AC_CHECK_GTK2], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(gtktest,,,enable_gtktest=yes) pkg_config_args=gtk+-2.0 for module in . $4 do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test x$PKG_CONFIG != xno ; then if pkg-config --atleast-pkgconfig-version 0.7 ; then : else echo "*** pkg-config too old; version 0.7 or better required." no_gtk=yes PKG_CONFIG=no fi else no_gtk=yes fi min_gtk_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GTK+ - version >= $min_gtk_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG --atleast-version $min_gtk_version $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" dnl dnl Now check if the installed GTK+ is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.gtktest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.gtktest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_gtk_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-2.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then AC_MSG_RESULT(yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" AC_TRY_LINK([ #include #include ], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) rm -f conf.gtktest ]) ekg-1.9~pre+r2855/m4/openssl.m4000066400000000000000000000040551174410337000160700ustar00rootroot00000000000000dnl based on curses.m4 dnl $Id$ AC_DEFUN([AC_CHECK_OPENSSL],[ AC_SUBST(OPENSSL_LIBS) AC_SUBST(OPENSSL_INCLUDES) AC_ARG_WITH(openssl, [[ --without-openssl Compile without OpenSSL]], if test "x$withval" = "xno" ; then without_openssl=yes elif test "x$withval" != "xyes" ; then with_arg=$withval/include:-L$withval/lib fi) if test "x$without_openssl" != "xyes" -a "x$with_arg" = "x"; then AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no]) if test "x$PKGCONFIG" != "xno"; then AC_MSG_CHECKING([for OpenSSL]) OPENSSL_LIBS=$($PKGCONFIG --libs openssl) OPENSSL_INCLUDES=$($PKGCONFIG --cflags openssl) if test "x$OPENSSL_LIBS" != "x" -o "x$OPENSSL_INCLUDES" != "x"; then AC_DEFINE(HAVE_OPENSSL, 1, [define if you have OpenSSL]) AC_MSG_RESULT([yes]) without_openssl=yes have_openssl=yes else AC_MSG_RESULT([no]) fi fi fi if test "x$without_openssl" != "xyes" ; then AC_MSG_CHECKING(for ssl.h) for i in $with_arg \ /usr/include: \ /usr/local/include:"-L/usr/local/lib" \ /usr/local/ssl/include:"-L/usr/local/ssl/lib" \ /usr/pkg/include:"-L/usr/pkg/lib" \ /usr/contrib/include:"-L/usr/contrib/lib" \ /usr/freeware/include:"-L/usr/freeware/lib32" \ /sw/include:"-L/sw/lib" \ /cw/include:"-L/cw/lib" \ /boot/home/config/include:"-L/boot/home/config/lib"; do incl=`echo "$i" | sed 's/:.*//'` lib=`echo "$i" | sed 's/.*://'` if test -f $incl/openssl/ssl.h; then AC_MSG_RESULT($incl/openssl/ssl.h) ldflags_old="$LDFLAGS" LDFLAGS="$lib -lssl -lcrypto" save_LIBS="$LIBS" LIBS="-lssl -lcrypto $LIBS" AC_CHECK_LIB(ssl, RSA_new, [ AC_DEFINE(HAVE_OPENSSL, 1, [define if you have OpenSSL]) have_openssl=yes OPENSSL_LIBS="$lib -lssl -lcrypto" if test "x$incl" != "x/usr/include"; then OPENSSL_INCLUDES="-I$incl" fi ]) LIBS="$save_LIBS" LDFLAGS="$ldflags_old" break fi done if test "x$have_openssl" != "xyes"; then AC_MSG_RESULT(not found) fi fi ]) ekg-1.9~pre+r2855/m4/python.m4000066400000000000000000000043121174410337000157220ustar00rootroot00000000000000dnl Rewritten from scratch. --speedy dnl $Id$ PYTHON= PYTHON_VERSION= PYTHON_INCLUDES= PYTHON_LIBS= AC_DEFUN([AC_CHECK_PYTHON],[ AC_SUBST(PYTHON_LIBS) AC_SUBST(PYTHON_INCLUDES) AC_ARG_WITH(python, [[ --with-python Compile with Python bindings]], if test "x$withval" != "xno" -a "x$withval" != "xyes"; then with_arg="$withval/include:-L$withval/lib $withval/include/python:-L$withval/lib" fi ) if test "x$with_python" = "xyes"; then AC_PATH_PROG(PYTHON, python) if test "$PYTHON" = ""; then AC_PATH_PROG(PYTHON, python2.2) fi if test "$PYTHON" = ""; then AC_PATH_PROG(PYTHON, python2.1) fi if test "$PYTHON" = ""; then AC_PATH_PROG(PYTHON, python2.0) fi if test "$PYTHON" != ""; then PY_VERSION=`$PYTHON -c "import sys; print sys.version[[0:3]]"` PY_PREFIX=`$PYTHON -c "import sys; print sys.prefix"` echo "Found Python version $PY_VERSION [$PY_PREFIX]" fi AC_MSG_CHECKING(for Python.h) PY_EXEC_PREFIX=`$PYTHON -c "import sys; print sys.exec_prefix"` if test "$PY_VERSION" != ""; then if test -f $PY_PREFIX/include/python$PY_VERSION/Python.h ; then AC_MSG_RESULT($PY_PREFIX/include/python$PY_VERSION/Python.h) PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python$PY_VERSION/config" PY_CFLAGS="-I$PY_PREFIX/include/python$PY_VERSION" PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python$PY_VERSION/config/Makefile" PY_LOCALMODLIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE` PY_BASEMODLIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE` PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE` PY_OTHER_LIBM=`sed -n -e 's/^LIBC=\(.*\)/\1/p' $PY_MAKEFILE` PY_OTHER_LIBC=`sed -n -e 's/^LIBM=\(.*\)/\1/p' $PY_MAKEFILE` PY_LINKFORSHARED="$(python -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LINKFORSHARED')")" PY_LIBS="$PY_LOCALMODLIBS $PY_BASEMODLIBS $PY_OTHER_LIBS $PY_OTHER_LIBC $PY_OTHER_LIBM $PY_LINKFORSHARED" PYTHON_LIBS="-L$PY_EXEC_PREFIX/lib $PY_LIB_LOC -lpython$PY_VERSION $PY_LIBS" PYTHON_INCLUDES="$PY_CFLAGS" AC_DEFINE(WITH_PYTHON, 1, [define if You want python]) have_python=yes fi fi if test "x$have_python" != "xyes"; then AC_MSG_RESULT(not found) fi fi ]) ekg-1.9~pre+r2855/m4/readline.m4000066400000000000000000000034261174410337000161710ustar00rootroot00000000000000dnl Rewritten from scratch. --wojtekka dnl $Id$ AC_DEFUN([AC_CHECK_READLINE],[ AC_SUBST(READLINE_LIBS) AC_SUBST(READLINE_INCLUDES) AC_ARG_WITH(readline, [[ --with-readline[=dir] Compile with readline/locate base dir]], if test "x$withval" = "xno" ; then without_readline=yes elif test "x$withval" != "xyes" ; then with_arg="$withval/include:-L$withval/lib $withval/include/readline:-L$withval/lib" fi) AC_MSG_CHECKING(for readline.h) if test "x$without_readline" != "xyes"; then for i in $with_arg \ /usr/include: \ /usr/local/include:-L/usr/local/lib \ /usr/freeware/include:-L/usr/freeware/lib32 \ /usr/pkg/include:-L/usr/pkg/lib \ /sw/include:-L/sw/lib \ /cw/include:-L/cw/lib \ /net/caladium/usr/people/piotr.nba/temp/pkg/include:-L/net/caladium/usr/people/piotr.nba/temp/pkg/lib \ /boot/home/config/include:-L/boot/home/config/lib; do incl=`echo "$i" | sed 's/:.*//'` lib=`echo "$i" | sed 's/.*://'` if test -f $incl/readline/readline.h ; then AC_MSG_RESULT($incl/readline/readline.h) READLINE_LIBS="$lib -lreadline" if test "$incl" != "/usr/include"; then READLINE_INCLUDES="-I$incl/readline -I$incl" else READLINE_INCLUDES="-I$incl/readline" fi AC_DEFINE(HAVE_READLINE, 1, [define if You want readline]) have_readline=yes break elif test -f $incl/readline.h -a "x$incl" != "x/usr/include"; then AC_MSG_RESULT($incl/readline.h) READLINE_LIBS="$lib -lreadline" READLINE_INCLUDES="-I$incl" AC_DEFINE(HAVE_READLINE, 1, [define if You want readline]) have_readline=yes break fi done fi if test "x$have_readline" != "xyes"; then AC_MSG_RESULT(not found) fi ]) ekg-1.9~pre+r2855/m4/stdint.m4000066400000000000000000000027151174410337000157130ustar00rootroot00000000000000dnl Based on AC_NEED_STDINT_H by Guido Draheim that can be dnl found at http://www.gnu.org/software/ac-archive/. Do not complain him dnl about this macro. dnl dnl $Id$ AC_DEFUN([AC_NEED_STDINT_H], [AC_MSG_CHECKING([for uintXX_t types]) if test "x$1" = "x"; then ac_stdint_h="stdint.h" else ac_stdint_h="$1" fi rm -f $ac_stdint_h ac_header_stdint="" for i in stdint.h inttypes.h sys/inttypes.h sys/int_types.h sys/types.h; do if test "x$ac_header_stdint" = "x"; then AC_TRY_COMPILE([#include <$i>], [uint32_t foo], [ac_header_stdint=$i]) fi done if test "x$ac_header_stdint" != "x" ; then AC_MSG_RESULT([found in <$ac_header_stdint>]) STDINT_H="$ac_header_stdint" if test "x$ac_header_stdint" != "xstdint.h" ; then echo "#include <$ac_header_stdint>" > $ac_stdint_h fi else AC_MSG_RESULT([not found, using reasonable defaults]) STDINT_H="" dnl let's make newer autoconf versions happy. stdint_h_foobar=define m4_pattern_allow([^__AC_STDINT_H$]) cat > $ac_stdint_h << EOF #ifndef __AC_STDINT_H #$stdint_h_foobar __AC_STDINT_H 1 /* ISO C 9X: 7.18 Integer types */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __CYGWIN__ #define __int8_t_defined typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; #endif #endif /* __AC_STDINT_H */ EOF fi ]) ekg-1.9~pre+r2855/src/000077500000000000000000000000001174410337000144065ustar00rootroot00000000000000ekg-1.9~pre+r2855/src/.cvsignore000066400000000000000000000001001174410337000163750ustar00rootroot00000000000000Makefile ekg ekg.log ioctld *.orig *.rej .DS_Store vekg .depend ekg-1.9~pre+r2855/src/COPYING000066400000000000000000000431311174410337000154430ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ekg-1.9~pre+r2855/src/Makefile.in000066400000000000000000000032001174410337000164460ustar00rootroot00000000000000# $Id$ srcdir= @srcdir@ prefix = @prefix@ datarootdir = @datarootdir@ datadir = @datadir@ mandir = @mandir@ exec_prefix = @exec_prefix@ bindir = @bindir@ libexecdir = @libexecdir@ sysconfdir = @sysconfdir@ CC = @CC@ CFLAGS = -I.. -I$(srcdir) -I$(srcdir)/.. @CFLAGS@ -DDATADIR=\"${datadir}/ekg\" -DSYSCONFDIR=\"${sysconfdir}\" LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ MAKE = @MAKE@ AR = @AR@ INSTALL = @INSTALL@ STRIP = @STRIP@ OBJS = stuff.o commands.o events.o themes.o vars.o dynstuff.o userlist.o ekg.o xmalloc.o mail.o msgqueue.o emoticons.o configfile.o @OBJS@ ui-batch.o ui-none.o log.o SRCS = $(patsubst %.o,$(srcdir)/%.c,$(OBJS)) $(srcdir)/comptime.c %.o: $(srcdir)/%.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $< ../compat/%.o: $(srcdir)/../compat/%.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $< # all: dep ekg @ioctld@ ekg: $(OBJS) $(srcdir)/comptime.c $(CC) $(CPPFLAGS) $(CFLAGS) -c -o comptime.o $(srcdir)/comptime.c $(CC) $(CFLAGS) -o ekg $(OBJS) comptime.o $(LDFLAGS) $(LIBS) ioctld: $(srcdir)/ioctld.c $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LIBS) @IOCTLD_OBJS@ dep: .depend .depend: $(SRCS) $(CC) -MM $(CFLAGS) $(SRCS) 1> .depend # install: all install-ekg @install_ioctld@ install-ekg: @strip_ekg@ $(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) -m 755 ekg $(DESTDIR)$(bindir) install-ioctld: @strip_ioctld@ $(INSTALL) -d $(DESTDIR)$(libexecdir) $(INSTALL) -m 755 ioctld $(DESTDIR)$(libexecdir) strip-ekg: $(STRIP) ekg strip-ioctld: $(STRIP) ioctld # clean: rm -f *.o ekg ioctld search core .depend distclean: clean rm -f *~ Makefile # ifneq ($(wildcard .depend),) include .depend endif ekg-1.9~pre+r2855/src/commands.c000066400000000000000000004762401174410337000163700ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2008 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Wojciech Bojdoł * Piotr Wysocki * Dawid Jarosz * Piotr Domagalski * Kuba Kowalski * Piotr Kupisiewicz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_REGEX_H # include #endif #include "commands.h" #include "configfile.h" #include "dynstuff.h" #include "events.h" #include "libgadu.h" #include "log.h" #include "msgqueue.h" #ifdef HAVE_OPENSSL # include "simlite.h" #endif #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "vars.h" #include "version.h" #include "voice.h" #include "userlist.h" #include "xmalloc.h" #ifdef WITH_PYTHON # include "python.h" #endif #include "comptime.h" COMMAND(cmd_ignore); COMMAND(cmd_msg); COMMAND(cmd_modify); COMMAND(cmd_check_conn); char *send_nicks[SEND_NICKS_MAX] = { NULL }; int send_nicks_count = 0, send_nicks_index = 0; int quit_command = 0; int change_quiet = 0; list_t commands = NULL; /* * match_arg() * * sprawdza, czy dany argument funkcji pasuje do podanego. */ int match_arg(const char *arg, char shortopt, const char *longopt, int longoptlen) { if (!arg || *arg != '-') return 0; arg++; if (*arg == '-') { int len = strlen(++arg); if (longoptlen > len) len = longoptlen; return !strncmp(arg, longopt, len); } return (*arg == shortopt) && (*(arg + 1) == 0); } /* * add_send_nick() * * dodaje do listy nicków dopełnianych automagicznie tabem. */ void add_send_nick(const char *nick) { int i; for (i = 0; i < send_nicks_count; i++) if (send_nicks[i] && !strcmp(nick, send_nicks[i])) { remove_send_nick(nick); break; } if (send_nicks_count == SEND_NICKS_MAX) { xfree(send_nicks[SEND_NICKS_MAX - 1]); send_nicks_count--; } for (i = send_nicks_count; i > 0; i--) send_nicks[i] = send_nicks[i - 1]; if (send_nicks_count != SEND_NICKS_MAX) send_nicks_count++; send_nicks[0] = xstrdup(nick); } /* * remove_send_nick() * * usuwa z listy dopełnianych automagicznie tabem. */ void remove_send_nick(const char *nick) { int i, j; for (i = 0; i < send_nicks_count; i++) { if (send_nicks[i] && !strcmp(send_nicks[i], nick)) { xfree(send_nicks[i]); for (j = i + 1; j < send_nicks_count; j++) send_nicks[j - 1] = send_nicks[j]; send_nicks_count--; send_nicks[send_nicks_count] = NULL; break; } } } COMMAND(cmd_cleartab) { int i; if (!params[0]) { for (i = 0; i < send_nicks_count; i++) { xfree(send_nicks[i]); send_nicks[i] = NULL; } send_nicks_count = 0; send_nicks_index = 0; printq("tab_cleared"); return 0; } if (match_arg(params[0], 'o', "offline", 2)) { for (i = 0; i < send_nicks_count; i++) { struct userlist *u = NULL; if (send_nicks[i]) u = userlist_find(atoi(send_nicks[i]), send_nicks[i]); if (!u || !GG_S_NA(u->status)) continue; remove_send_nick(send_nicks[i]); } printq("tab_cleared"); return 0; } printq("invalid_params", name); return -1; } COMMAND(cmd_add) { int params_free = 0, result = 0; struct userlist *u = NULL; uin_t uin = 0, __uin; list_t l; ui_event("command", quiet, "query-current", &__uin, NULL); if (params[0] && !match_arg(params[0], 'f', "find", 2) && strcmp(params[0], "$") && !str_to_uin(params[0]) && __uin && (!(u = userlist_find(__uin, NULL)) || !u->display)) { const char *name = NULL, *s1 = NULL, *s2 = NULL; if (params[0]) { name = params[0]; if (params[1]) { s1 = params[1]; if (params[2]) s2 = params[2]; } } uin = __uin; params_free = 1; params = xmalloc(4 * sizeof(char *)); params[0] = itoa(uin); params[1] = name; if (s1) params[2] = saprintf("%s %s", s1, ((s2) ? s2 : "")); else params[2] = NULL; params[3] = NULL; } if (params[0] && match_arg(params[0], 'f', "find", 2)) { int nonick = 0; char *nickname, *tmp; if (!last_search_uin || !last_search_nickname) { printq("search_no_last"); return -1; } tmp = strip_spaces(last_search_nickname); if ((nonick = !strcmp(tmp, "")) && !params[1]) { printq("search_no_last_nickname"); return -1; } if (nonick || params[1]) nickname = (char *) params[1]; else nickname = tmp; params_free = 1; params = xmalloc(4 * sizeof(char *)); params[0] = itoa(last_search_uin); params[1] = nickname; params[2] = saprintf("-f \"%s\" -l \"%s\"", ((last_search_first_name) ? last_search_first_name : ""), ((last_search_last_name) ? last_search_last_name : "")); params[3] = NULL; } if (!params[0] || !params[1]) { printq("not_enough_params", name); result = -1; goto cleanup; } if (!strcmp(params[0], "$")) uin = get_uin(params[0]); if (!uin && !(uin = str_to_uin(params[0]))) { printq("invalid_uin"); result = -1; goto cleanup; } if (!valid_nick(params[1])) { printq("invalid_nick"); result = -1; goto cleanup; } if ((u = userlist_find(uin, params[1])) && u->display) { if (!strcasecmp(params[1], u->display) && u->uin == uin) printq("user_exists", params[1]); else printq("user_exists_other", params[1], format_user(u->uin)); result = -1; goto cleanup; } /* ktoś był tylko ignorowany/blokowany, nadajmy mu nazwę */ if (u) u->display = xstrdup(params[1]); if (u || userlist_add(uin, params[1])) { printq("user_added", params[1]); if (sess) gg_add_notify_ex(sess, uin, userlist_type(u)); remove_send_nick(itoa(uin)); config_changed = 1; ui_event("userlist_changed", itoa(uin), params[1], NULL); if (uin == config_uin) { update_status(); update_status_myip(); } } if (params[2]) cmd_modify("add", ¶ms[1], NULL, quiet); for (l = autofinds; l; l = l->next) { uin_t *d = l->data; if (*d == uin) { list_remove(&autofinds, &uin, 1); break; } } cleanup: if (params_free) { xfree((char*) params[2]); xfree(params); } return result; } COMMAND(cmd_alias) { if (match_arg(params[0], 'a', "add", 2)) { if (!params[1] || !strchr(params[1], ' ')) { printq("not_enough_params", name); return -1; } if (!alias_add(params[1], quiet, 0)) { config_changed = 1; return 0; } return -1; } if (match_arg(params[0], 'A', "append", 2)) { if (!params[1] || !strchr(params[1], ' ')) { printq("not_enough_params", name); return -1; } if (!alias_add(params[1], quiet, 1)) { config_changed = 1; return 0; } return -1; } if (match_arg(params[0], 'd', "del", 2)) { int ret; if (!params[1]) { printq("not_enough_params", name); return -1; } if (!strcmp(params[1], "*")) ret = alias_remove(NULL, quiet); else ret = alias_remove(params[1], quiet); if (!ret) { config_changed = 1; return 0; } return -1; } if (!params[0] || match_arg(params[0], 'l', "list", 2) || params[0][0] != '-') { list_t l; int count = 0; const char *aname = NULL; if (params[0] && match_arg(params[0], 'l', "list", 2)) aname = params[1]; else if (params[0]) aname = params[0]; for (l = aliases; l; l = l->next) { struct alias *a = l->data; list_t m; int first = 1, i; char *tmp; if (aname && strcasecmp(aname, a->name)) continue; tmp = xcalloc(strlen(a->name) + 1, 1); for (i = 0; i < strlen(a->name); i++) strlcat(tmp, " ", strlen(a->name) + 1); for (m = a->commands; m; m = m->next) { printq((first) ? "aliases_list" : "aliases_list_next", a->name, (char*) m->data, tmp); first = 0; count++; } xfree(tmp); } if (!count) { if (aname) { printq("aliases_noexist", aname); return -1; } printq("aliases_list_empty"); } return 0; } printq("invalid_params", name); return -1; } COMMAND(cmd_away) { int q = (quiet) ? 2 : 0; in_auto_away = 0; if (params[0] && strlen(params[0]) > GG_STATUS_DESCR_MAXSIZE) { printq("descr_too_long", itoa(strlen(params[0]) - GG_STATUS_DESCR_MAXSIZE)); if (config_reason_limit) return -1; } if (!strcasecmp(name, "_descr")) change_status(config_status, params[0], q); if (!strcasecmp(name, "away")) change_status(GG_STATUS_BUSY, params[0], q); if (!strcasecmp(name, "invisible")) change_status(GG_STATUS_INVISIBLE, params[0], q); if (!strcasecmp(name, "back")) { change_status(GG_STATUS_AVAIL, params[0], q); sms_away_free(); } if (!strcasecmp(name, "ffc")) change_status(GG_STATUS_FFC, params[0], q); if (!strcasecmp(name, "dnd")) change_status(GG_STATUS_DND, params[0], q); if (!strcasecmp(name, "private")) { int tmp; if (!params[0]) { printq((GG_S_F(config_status) ? "private_mode_is_on" : "private_mode_is_off")); return 0; } if ((tmp = on_off(params[0])) == -1) { printq("private_mode_invalid"); return -1; } if (tmp == GG_S_F(config_status)) { printq(GG_S_F(config_status) ? "private_mode_is_on" : "private_mode_is_off"); return 0; } printq(((tmp) ? "private_mode_on" : "private_mode_off")); ui_event("my_status", "private", ((tmp) ? "on" : "off"), NULL); config_status = GG_S(config_status); config_status |= ((tmp) ? GG_STATUS_FRIENDS_MASK : 0); if (sess && sess->state == GG_STATE_CONNECTED) { gg_debug(GG_DEBUG_MISC, "-- config_status = 0x%.2x\n", config_status); if (config_reason) { iso_to_cp((unsigned char *) config_reason); gg_change_status_descr(sess, config_status, config_reason); cp_to_iso((unsigned char *) config_reason); } else gg_change_status(sess, config_status); } } unidle(); return 0; } COMMAND(cmd_status) { struct userlist *u; struct in_addr i; struct tm *t; time_t n; int mqc, now_days; char *tmp, *priv, *r1, *r2, buf[100], buf1[100]; if (strcmp(format_find("show_status_header"), "")) printq("show_status_header"); if (config_profile) printq("show_status_profile", config_profile); if ((u = userlist_find(config_uin, NULL)) && u->display) printq("show_status_uin_nick", itoa(config_uin), u->display); else printq("show_status_uin", itoa(config_uin)); n = time(NULL); t = localtime(&n); now_days = t->tm_yday; t = localtime(&last_conn_event); strftime(buf, sizeof(buf), format_find((t->tm_yday == now_days) ? "show_status_last_conn_event_today" : "show_status_last_conn_event"), t); t = localtime(&ekg_started); strftime(buf1, sizeof(buf1), format_find((t->tm_yday == now_days) ? "show_status_ekg_started_today" : "show_status_ekg_started"), t); if (!sess || sess->state != GG_STATE_CONNECTED) { char *tmp = format_string(format_find("show_status_not_avail")); printq("show_status_status", tmp, ""); printq("show_status_ekg_started_since", buf1); if (last_conn_event) printq("show_status_disconnected_since", buf); if ((mqc = msg_queue_count())) printq("show_status_msg_queue", itoa(mqc)); if (strcmp(format_find("show_status_footer"), "")) printq("show_status_footer"); xfree(tmp); return 0; } if (GG_S_F(config_status)) priv = format_string(format_find("show_status_private_on")); else priv = format_string(format_find("show_status_private_off")); r1 = xstrmid(config_reason, 0, GG_STATUS_DESCR_MAXSIZE); r2 = xstrmid(config_reason, GG_STATUS_DESCR_MAXSIZE, -1); tmp = format_string(format_find(ekg_status_label(config_status, "show_status_")), r1, r2); xfree(r1); xfree(r2); i.s_addr = sess->server_addr; printq("show_status_status", tmp, priv); printq("show_status_ekg_started_since", buf1); #ifdef __GG_LIBGADU_HAVE_OPENSSL if (sess->ssl) printq("show_status_server_tls", inet_ntoa(i), itoa(sess->port)); else #endif printq("show_status_server", inet_ntoa(i), itoa(sess->port)); printq("show_status_connected_since", buf); xfree(tmp); xfree(priv); if (strcmp(format_find("show_status_footer"), "")) printq("show_status_footer"); return 0; } COMMAND(cmd_connect) { if (!strcasecmp(name, "connect")) { if (sess) { printq((sess->state == GG_STATE_CONNECTED) ? "already_connected" : "during_connect"); return -1; } if (params && params[0] && params[1]) { variable_set("uin", params[0], 0); variable_set("password", params[1], 0); } if (params && params[0] && !params[1]) variable_set("password", params[0], 0); if (config_uin && config_password) { printq("connecting"); connecting = 1; ekg_connect(); } else { printq("no_config"); return -1; } } else if (!strcasecmp(name, "reconnect")) { cmd_connect("__disconnect", NULL, NULL, quiet); cmd_connect("connect", NULL, NULL, quiet); } else { char *tmp = NULL; if (!strcasecmp(name, "disconnect")) { if (!params || !params[0]) { if (config_random_reason & 2) { tmp = random_line(prepare_path("quit.reasons", 0)); if (!tmp && config_quit_reason) tmp = xstrdup(config_quit_reason); } else if (config_quit_reason) tmp = xstrdup(config_quit_reason); } else tmp = xstrdup(params[0]); if (config_keep_reason && config_reason && !tmp) tmp = xstrdup(config_reason); xfree(config_reason); config_reason = NULL; if (params && params[0] && !strcmp(params[0], "-")) { xfree(tmp); tmp = NULL; } if (config_keep_reason) config_reason = xstrdup(tmp); if (!config_reason) config_status = ekg_hide_descr_status(config_status); } else tmp = xstrdup(config_reason); connecting = 0; if (sess && sess->state == GG_STATE_CONNECTED) { if (tmp) { char *r1, *r2; r1 = xstrmid(tmp, 0, GG_STATUS_DESCR_MAXSIZE); r2 = xstrmid(tmp, GG_STATUS_DESCR_MAXSIZE, -1); printq("disconnected_descr", r1, r2); xfree(r1); xfree(r2); } else printq("disconnected"); } else if (reconnect_timer || (sess && sess->state != GG_STATE_IDLE)) printq("conn_stopped"); if (sess) { ekg_logoff(sess, tmp); xfree(tmp); list_remove(&watches, sess, 0); gg_free_session(sess); userlist_clear_status(0); sess = NULL; } reconnect_timer = 0; ui_event("disconnected", NULL); } return 0; } COMMAND(cmd_del) { struct userlist *u; const char *tmp; char *nick; char type; uin_t uin = 0; int del_all = ((params[0] && !strcmp(params[0], "*")) ? 1 : 0); if (!params[0]) { printq("not_enough_params", name); return -1; } if (del_all) { list_t l; for (l = userlist; l; ) { struct userlist *u = l->data; l = l->next; if (sess) gg_remove_notify_ex(sess, u->uin, userlist_type(u)); uin = u->uin; nick = xstrdup(u->display); if (!userlist_remove(u, 0)) ui_event("userlist_changed", nick, itoa(uin), NULL); xfree(nick); } printq("user_cleared_list"); command_exec(NULL, "/cleartab", 1); config_changed = 1; return 0; } if (!(u = userlist_find((uin = get_uin(params[0])), NULL)) || !u->display) { printq("user_not_found", params[0]); return -1; } nick = xstrdup(u->display); tmp = format_user(u->uin); type = userlist_type(u); if (!userlist_remove(u, 0)) { printq("user_deleted", tmp); if (sess) gg_remove_notify_ex(sess, uin, type); remove_send_nick(itoa(uin)); remove_send_nick(nick); config_changed = 1; ui_event("userlist_changed", nick, itoa(uin), NULL); } xfree(nick); return 0; } COMMAND(cmd_exec) { list_t l; int pid; if (params[0]) { char **args = NULL, *tmp, *tg = NULL; int fd[2] = { 0, 0 }, buf = 0, msg = 0, add_commandline = 0; const char *command = NULL; struct gg_exec s; if (params[0][0] == '-') { int big_match = 0; args = array_make(params[0], " \t", 3, 1, 1); if (match_arg(args[0], 'M', "MSG", 2) || (buf = match_arg(args[0], 'B', "BMSG", 2))) big_match = add_commandline = 1; if (big_match || match_arg(args[0], 'm', "msg", 2) || (buf = match_arg(args[0], 'b', "bmsg", 2))) { struct userlist *u; int uin; if (!args[1] || !args[2]) { printq("not_enough_params", name); array_free(args); return -1; } if (!(uin = get_uin(args[1]))) { printq("user_not_found", args[1]); array_free(args); return -1; } if ((u = userlist_find(uin, NULL)) && u->display) tg = xstrdup(u->display); else tg = xstrdup(itoa(uin)); msg = (buf) ? 2 : 1; command = args[2]; } else { printq("invalid_params", name); array_free(args); return -1; } } else command = params[0]; if (pipe(fd)) { printq("exec_error", strerror(errno)); xfree(tg); array_free(args); return -1; } if (!(pid = fork())) { dup2(open("/dev/null", O_RDONLY), 0); if (fd[1]) { close(fd[0]); dup2(fd[1], 2); dup2(fd[1], 1); close(fd[1]); } execl("/bin/sh", "sh", "-c", ((command[0] == '^' && strlen(command) > 1) ? command + 1 : command), (void *) NULL); exit(1); } if (pid < 0) { printq("exec_error", strerror(errno)); xfree(tg); array_free(args); return -1; } s.fd = fd[0]; s.check = GG_CHECK_READ; s.state = GG_STATE_READING_DATA; s.type = GG_SESSION_USER3; s.id = pid; s.timeout = -1; if (add_commandline) { char *tmp = format_string(format_find("exec_prompt"), ((command[0] == '^') ? command + 1 : command)); s.buf = string_init(tmp); xfree(tmp); } else s.buf = string_init(NULL); s.target = ((tg) ? tg : xstrdup(target)); s.msg = msg; s.quiet = quiet; fcntl(s.fd, F_SETFL, O_NONBLOCK); list_add(&watches, &s, sizeof(s)); close(fd[1]); if (quiet || command[0] == '^') tmp = saprintf("\002%s", command + 1); else tmp = xstrdup(command); process_add(pid, tmp); array_free(args); xfree(tmp); } else { for (l = children; l; l = l->next) { struct process *p = l->data; char *tmp = NULL; switch (p->name[0]) { case '\001': tmp = saprintf("wysyłanie sms do %s", p->name + 1); break; case '\002': tmp = saprintf("^%s", p->name + 1); break; case '\003': break; default: tmp = xstrdup(p->name); } if (tmp) printq("process", itoa(p->pid), tmp); xfree(tmp); } if (!children) { printq("no_processes"); return -1; } } return 0; } COMMAND(cmd_find) { char **argv = NULL, *user; gg_pubdir50_t req; int i, res = 0, all = 0; if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if (params[0] && match_arg(params[0], 'S', "stop", 3)) { list_t l; for (l = searches; l; ) { gg_pubdir50_t s = l->data; l = l->next; gg_pubdir50_free(s); list_remove(&searches, s, 0); } printq("search_stopped"); return 0; } if (!params[0] || !(argv = array_make(params[0], " \t", 0, 1, 1)) || !argv[0]) { ui_event("command", quiet, "find", NULL); array_free(argv); return -1; } if (argv[0] && !argv[1] && argv[0][0] == '#') { char *tmp = saprintf("/conference --find %s", argv[0]); int res = command_exec(target, tmp, quiet); xfree(tmp); array_free(argv); return res; } user = xstrdup(argv[0]); for (i = 0; argv[i]; i++) iso_to_cp((unsigned char *) argv[i]); if (!(req = gg_pubdir50_new(GG_PUBDIR50_SEARCH))) { array_free(argv); xfree(user); return -1; } if (argv[0] && argv[0][0] != '-') { uin_t uin = get_uin(user); if (!uin) { printq("user_not_found", user); array_free(argv); xfree(user); return -1; } gg_pubdir50_add(req, GG_PUBDIR50_UIN, itoa(uin)); i = 1; } else i = 0; xfree(user); for (; argv[i]; i++) { char *arg = argv[i]; if (match_arg(arg, 'f', "first", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_FIRSTNAME, argv[++i]); continue; } if (match_arg(arg, 'l', "last", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_LASTNAME, argv[++i]); continue; } if (match_arg(arg, 'n', "nickname", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_NICKNAME, argv[++i]); continue; } if (match_arg(arg, 'c', "city", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_CITY, argv[++i]); continue; } if (match_arg(arg, 'u', "uin", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_UIN, itoa(get_uin(argv[++i]))); continue; } if (match_arg(arg, 's', "start", 3) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_START, argv[++i]); continue; } if (match_arg(arg, 'F', "female", 2)) { gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_FEMALE); continue; } if (match_arg(arg, 'M', "male", 2)) { gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_MALE); continue; } if (match_arg(arg, 'a', "active", 2)) { gg_pubdir50_add(req, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE); continue; } if (match_arg(arg, 'b', "born", 2) && argv[i + 1]) { char *foo = strchr(argv[++i], ':'); if (foo) *foo = ' '; gg_pubdir50_add(req, GG_PUBDIR50_BIRTHYEAR, argv[i]); continue; } if (match_arg(arg, 'A', "all", 3)) { if (!gg_pubdir50_get(req, 0, GG_PUBDIR50_START)) gg_pubdir50_add(req, GG_PUBDIR50_START, "0"); all = 1; continue; } printq("invalid_params", name); array_free(argv); gg_pubdir50_free(req); return -1; } if (!gg_pubdir50(sess, req)) { printq("search_failed", http_error_string(0)); res = -1; } if (all) list_add(&searches, req, 0); else gg_pubdir50_free(req); array_free(argv); return res; } COMMAND(cmd_for) { int from, to, step = 0; char **argv, *cmd; int equal_width = 0; int width = 0; int ofs = 0; int i; if (!params[0]) { printq("not_enough_params", name); return -1; } argv = array_make(params[0], " \t", 0, 1, 1); for (i = 0; argv[i]; i++) { if (match_arg(argv[i], 's', "step", 2)) { if (!argv[i + 1]) { printq("invalid_params", name); array_free(argv); return -1; } step = atoi(argv[i + 1]); ofs += 2; i++; } else if (match_arg(argv[i], 'w', "width", 2)) { equal_width = 1; ofs++; } } if (!argv[ofs] || !argv[ofs + 1] || !argv[ofs + 2]) { printq("not_enough_params", name); array_free(argv); return -1; } from = atoi(argv[ofs]); to = atoi(argv[ofs + 1]); if ((from > to && step > 0) || (from < to && step < 0)) { printq("invalid_params", name); array_free(argv); return -1; } if (!step) step = (from > to) ? -1 : 1; if (equal_width) { int l1, l2; l1 = strlen(argv[ofs]); l2 = strlen(argv[ofs + 1]); width = (l1 > l2) ? l1 : l2; } array_free(argv); argv = array_make(params[0], " \t", ofs + 3, 1, 1); cmd = xstrdup(argv[ofs + 2]); array_free(argv); // gg_debug(GG_DEBUG_MISC, "from=%d to=%d step=%d width=%d cmd=%s\n", from, to, step, equal_width, cmd); while ((step > 0) ? (from <= to) : (from >= to)) { char *buf = xstrdup(itoa(from)); string_t rcmd; char *p; if (equal_width) { int orig_width = strlen(buf); char *buf2 = (char *) xmalloc(width + 1); int start_buf = 0, start_buf2; /* zamieniamy: 123 -> 0123, -123 -> -0123 */ memset(buf2, '0', width); buf2[width] = 0; if (buf[0] == '-') { buf2[0] = '-'; start_buf++; } start_buf2 = (width - orig_width) + start_buf; memcpy(buf2 + start_buf2, buf + start_buf, orig_width - start_buf); xfree(buf); buf = buf2; } rcmd = string_init(NULL); /* cmd wskazuje na stringa, którego należy przepisać do rcmd, zamieniając * wszystkie wystąpienia %n na zawartość bufora (buf) a wystąpienia %% * na %. %cośinnego zostawiamy tak jak jest. */ if (*cmd != '/') string_append_c(rcmd, '/'); for (p = cmd; *p; p++) { if (p[0] == '%' && p[1] == '%') { string_append_c(rcmd, '%'); p++; } else if (p[0] == '%' && p[1] == 'n') { string_append(rcmd, buf); p++; } else string_append_c(rcmd, *p); } command_exec(target, rcmd->str, quiet); string_free(rcmd, 1); from += step; } return 0; } COMMAND(cmd_change) { int i; gg_pubdir50_t req; if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if (!params[0]) { printq("not_enough_params", name); return -1; } if (!(req = gg_pubdir50_new(GG_PUBDIR50_WRITE))) return -1; if (strcmp(params[0], "-")) { char **argv = array_make(params[0], " \t", 0, 1, 1); for (i = 0; argv[i]; i++) iso_to_cp((unsigned char *) argv[i]); for (i = 0; argv[i]; i++) { if (match_arg(argv[i], 'f', "first", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_FIRSTNAME, argv[++i]); continue; } if (match_arg(argv[i], 'N', "familyname", 7) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_FAMILYNAME, argv[++i]); continue; } if (match_arg(argv[i], 'l', "last", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_LASTNAME, argv[++i]); continue; } if (match_arg(argv[i], 'n', "nickname", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_NICKNAME, argv[++i]); continue; } if (match_arg(argv[i], 'c', "city", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_CITY, argv[++i]); continue; } if (match_arg(argv[i], 'C', "familycity", 7) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_FAMILYCITY, argv[++i]); continue; } if (match_arg(argv[i], 'b', "born", 2) && argv[i + 1]) { gg_pubdir50_add(req, GG_PUBDIR50_BIRTHYEAR, argv[++i]); continue; } if (match_arg(argv[i], 'F', "female", 2)) { gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_SET_FEMALE); continue; } if (match_arg(argv[i], 'M', "male", 2)) { gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_SET_MALE); continue; } printq("invalid_params", name); gg_pubdir50_free(req); array_free(argv); return -1; } array_free(argv); } if (!gg_pubdir50(sess, req)) { printq("change_failed", ""); gg_pubdir50_free(req); return -1; } gg_pubdir50_free(req); change_quiet = quiet; return 0; } COMMAND(cmd_modify) { struct userlist *u; char **argv = NULL; int i, res = 0, modified = 0; if (!params[0]) { printq("not_enough_params", name); return -1; } if (!(u = userlist_find(get_uin(params[0]), NULL))) { printq("user_not_found", params[0]); return -1; } argv = array_make(params[1], " \t", 0, 1, 1); for (i = 0; argv[i]; i++) { if (match_arg(argv[i], 'f', "first", 2) && argv[i + 1]) { xfree(u->first_name); u->first_name = xstrdup(argv[++i]); if (!strcmp(u->first_name, "")) { xfree(u->first_name); u->first_name = NULL; } modified = 1; continue; } if (match_arg(argv[i], 'l', "last", 2) && argv[i + 1]) { xfree(u->last_name); u->last_name = xstrdup(argv[++i]); if (!strcmp(u->last_name, "")) { xfree(u->last_name); u->last_name = NULL; } modified = 1; continue; } if (match_arg(argv[i], 'e', "email", 2) && argv[i + 1]) { xfree(u->email); u->email = xstrdup(argv[++i]); if (!strcmp(u->email, "")) { xfree(u->email); u->email = NULL; } modified = 1; continue; } if (match_arg(argv[i], 'n', "nickname", 2) && argv[i + 1]) { xfree(u->nickname); u->nickname = xstrdup(argv[++i]); if (!strcmp(u->nickname, "")) { xfree(u->nickname); u->nickname = NULL; } modified = 1; continue; } if (match_arg(argv[i], 'p', "phone", 2) && argv[i + 1]) { xfree(u->mobile); u->mobile = xstrdup(argv[++i]); if (!strcmp(u->mobile, "")) { xfree(u->mobile); u->mobile = NULL; } modified = 1; continue; } if (match_arg(argv[i], 'd', "display", 2) && argv[i + 1]) { i++; if (!valid_nick(argv[i])) { printq("invalid_nick"); array_free(argv); return -1; } if (userlist_find(0, argv[i])) { printq("user_exists", argv[i]); array_free(argv); return -1; } ui_event("userlist_changed", ((u->display) ? u->display : itoa(u->uin)), argv[i], NULL); remove_send_nick(u->display); xfree(u->display); u->display = xstrdup(argv[i]); userlist_replace(u); add_send_nick(u->display); modified = 1; continue; } if (match_arg(argv[i], 'g', "group", 2) && argv[i + 1]) { char **tmp = array_make(argv[++i], ",", 0, 1, 1); int x, off; /* jeśli zaczyna się od '@', pomijamy pierwszy znak */ for (x = 0; tmp[x]; x++) switch (*tmp[x]) { case '-': off = (tmp[x][1] == '@' && strlen(tmp[x]) > 1) ? 1 : 0; if (group_member(u, tmp[x] + 1 + off)) { group_remove(u, tmp[x] + 1 + off); modified = 1; } else { printq("group_member_not_yet", format_user(u->uin), tmp[x] + 1); if (!modified) modified = -1; } break; case '+': off = (tmp[x][1] == '@' && strlen(tmp[x]) > 1) ? 1 : 0; if (!group_member(u, tmp[x] + 1 + off)) { group_add(u, tmp[x] + 1 + off); modified = 1; } else { printq("group_member_already", format_user(u->uin), tmp[x] + 1); if (!modified) modified = -1; } break; default: off = (tmp[x][0] == '@' && strlen(tmp[x]) > 1) ? 1 : 0; if (!group_member(u, tmp[x] + off)) { group_add(u, tmp[x] + off); modified = 1; } else { printq("group_member_already", format_user(u->uin), tmp[x]); if (!modified) modified = -1; } } array_free(tmp); continue; } if (match_arg(argv[i], 'u', "uin", 2) && argv[i + 1]) { uin_t new_uin = str_to_uin(argv[++i]); struct userlist *existing; if (!new_uin) { printq("invalid_uin"); array_free(argv); return -1; } if ((existing = userlist_find(new_uin, NULL))) { if (existing->display) { printq("user_exists_other", argv[i], format_user(existing->uin)); array_free(argv); return -1; } else { char *egroups = group_to_string(existing->groups, 1, 0); if (egroups) { char **arr = array_make(egroups, ",", 0, 0, 0); int i; for (i = 0; arr[i]; i++) group_add(u, arr[i]); array_free(arr); } userlist_remove(existing, 0); } } gg_remove_notify_ex(sess, u->uin, userlist_type(u)); userlist_clear_status(u->uin); u->uin = new_uin; gg_add_notify_ex(sess, u->uin, userlist_type(u)); ui_event("userlist_changed", u->display, u->display, NULL); modified = 1; continue; } if (match_arg(argv[i], 'o', "offline", 2)) { gg_remove_notify_ex(sess, u->uin, userlist_type(u)); group_add(u, "__offline"); printq("modify_offline", format_user(u->uin)); modified = 2; gg_add_notify_ex(sess, u->uin, userlist_type(u)); continue; } if (match_arg(argv[i], 'O', "online", 2)) { gg_remove_notify_ex(sess, u->uin, userlist_type(u)); group_remove(u, "__offline"); printq("modify_online", format_user(u->uin)); modified = 2; gg_add_notify_ex(sess, u->uin, userlist_type(u)); continue; } printq("invalid_params", name); array_free(argv); return -1; } if (strcasecmp(name, "add")) { switch (modified) { case 0: printq("not_enough_params", name); res = -1; break; case 1: printq("modify_done", params[0]); case 2: config_changed = 1; break; } } else config_changed = 1; array_free(argv); return res; } COMMAND(cmd_help) { list_t l; if (params[0]) { const char *p = (params[0][0] == '/' && strlen(params[0]) > 1) ? params[0] + 1 : params[0]; if (!strcasecmp(p, "set") && params[1]) { if (!quiet) variable_help(params[1]); return 0; } for (l = commands; l; l = l->next) { struct command *c = l->data; if (!strcasecmp(c->name, p) && c->alias) { printq("help_alias", p); return -1; } if (!strcasecmp(c->name, p) && !c->alias) { char *tmp = NULL; if (strstr(c->brief_help, "%")) tmp = format_string(c->brief_help); printq("help", c->name, c->params_help, tmp ? tmp : c->brief_help, ""); xfree(tmp); if (c->long_help && strcmp(c->long_help, "")) { char *foo, *tmp, *bar = format_string(c->long_help); foo = bar; while ((tmp = get_line(&foo))) printq("help_more", tmp); xfree(bar); } return 0; } } } for (l = commands; l; l = l->next) { struct command *c = l->data; if (xisalnum(*c->name) && !c->alias) { char *blah = NULL; if (strstr(c->brief_help, "%")) blah = format_string(c->brief_help); printq("help", c->name, c->params_help, blah ? blah : c->brief_help, ""); xfree(blah); } } printq("help_footer"); printq("help_quick"); return 0; } int ignore_group_wrapper(const char *name, const char *group, const char *level, const char *target, int quiet) { list_t l; int ret = 0, any = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (group_member(u, group + 1)) { const char *params[] = { u->display, level, NULL }; any = 1; if (cmd_ignore(name, params, target, quiet)) ret = 1; } } if (!any) printq("group_empty", group); return ret; } COMMAND(cmd_ignore) { char *tmp; uin_t uin = 0; if (*name == 'i' || *name == 'I') { int flags, modified = 0; if (!params[0]) { list_t l; int i = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; int level; if (!(level = ignored_check(u->uin))) continue; i = 1; printq("ignored_list", format_user(u->uin), ignore_format(level)); } if (config_ignore_unknown_sender) { i = 1; printq("ignored_list_unknown_sender"); } if (!i) printq("ignored_list_empty"); return 0; } if (params[0][0] == '#') { int res; tmp = saprintf("/conference --ignore %s", params[0]); res = command_exec(target, tmp, quiet); xfree(tmp); return res; } if (params[0][0] == '@') return ignore_group_wrapper(name, params[0], params[1], target, quiet); if ((flags = ignored_check(get_uin(params[0])))) modified = 1; if (params[1]) { int __flags = ignore_flags(params[1]); if (!__flags) { printq("invalid_params", name); return -1; } flags |= __flags; } else flags |= IGNORE_ALL; if (!(uin = get_uin(params[0]))) { printq("user_not_found", params[0]); return -1; } if (ignored_check(uin)) ignored_remove(uin); if (!ignored_add(uin, flags)) { if (modified) printq("ignored_modified", format_user(uin)); else printq("ignored_added", format_user(uin)); config_changed = 1; } } else { int unignore_all = ((params[0] && !strcmp(params[0], "*")) ? 1 : 0); int level; if (!params[0]) { printq("not_enough_params", name); return -1; } if (params[0][0] == '#') { int res; tmp = saprintf("/conference --unignore %s", params[0]); res = command_exec(target, tmp, quiet); xfree(tmp); return res; } if (params[0][0] == '@') return ignore_group_wrapper(name, params[0], params[1], target, quiet); if (!unignore_all && !(uin = get_uin(params[0]))) { printq("user_not_found", params[0]); return -1; } if (unignore_all) { list_t l; int x = 0; for (l = userlist; l; ) { struct userlist *u = l->data; l = l->next; if (!ignored_remove(u->uin)) x = 1; level = ignored_check(u->uin); if (uin == config_uin) update_status(); } if (x) { printq("ignored_deleted_all"); config_changed = 1; } else { printq("ignored_list_empty"); return -1; } return 0; } level = ignored_check(uin); if (!ignored_remove(uin)) { printq("ignored_deleted", format_user(uin)); if (uin == config_uin) update_status(); config_changed = 1; } else { printq("error_not_ignored", format_user(uin)); return -1; } } return 0; } COMMAND(cmd_block) { uin_t uin; if (*name == 'b' || *name == 'B') { if (!params[0]) { list_t l; int i = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!group_member(u, "__blocked")) continue; i = 1; printq("blocked_list", format_user(u->uin)); } if (!i) printq("blocked_list_empty"); return 0; } if (!(uin = get_uin(params[0]))) { printq("user_not_found", params[0]); return -1; } if (!blocked_add(uin)) { printq("blocked_added", format_user(uin)); config_changed = 1; } else { printq("blocked_exist", format_user(uin)); return -1; } } else { int unblock_all = ((params[0] && !strcmp(params[0], "*")) ? 1 : 0); if (!params[0]) { printq("not_enough_params", name); return -1; } if (unblock_all) { list_t l; int x = 0; for (l = userlist; l; ) { struct userlist *u = l->data; l = l->next; if (!blocked_remove(u->uin)) x = 1; } if (x) { printq("blocked_deleted_all"); config_changed = 1; } else { printq("blocked_list_empty"); return -1; } return 0; } if (!(uin = get_uin(params[0]))) { printq("user_not_found", params[0]); return -1; } if (!blocked_remove(uin)) { printq("blocked_deleted", format_user(uin)); config_changed = 1; } else { printq("error_not_blocked", format_user(uin)); return -1; } } return 0; } COMMAND(cmd_list) { list_t l; int count = 0, show_all = 1, show_busy = 0, show_active = 0, show_group_inverted = 0; int show_inactive = 0, show_invisible = 0, show_descr = 0, show_blocked = 0, show_offline = 0, j; int show_ffc = 0, show_dnd = 0; char **argv = NULL, *show_group = NULL, *ip_str; const char *tmp; int params_null = 0; uin_t uin; if (!params[0] && (uin = get_uin("$"))) { params_null = 1; params[0] = itoa(uin); } if (params[0] && *params[0] != '-') { char *status, *groups; const char *group = params[0]; struct userlist *u; int invert = 0, i; /* list !@grupa */ if (group[0] == '!' && group[1] == '@') { group++; invert = 1; } /* list @grupa */ if (group[0] == '@' && strlen(group) > 1) { string_t members = string_init(NULL); char *__group; int count = 0; for (l = userlist; l; l = l->next) { u = l->data; if (u->groups || invert) { if ((!invert && group_member(u, group + 1)) || (invert && !group_member(u, group + 1))) { if (count++) string_append(members, ", "); string_append(members, u->display); } } } __group = saprintf("%s%s", ((invert) ? "!" : ""), group + 1); if (count) printq("group_members", __group, members->str); else printq("group_empty", __group); xfree(__group); string_free(members, 1); return 0; } if (!(u = userlist_find(get_uin(params[0]), NULL)) || !u->display) { printq("user_not_found", params[0]); if (params_null) params[0] = NULL; return -1; } /* list [opcje] */ if (!params_null && params[1]) return cmd_modify("list", params, NULL, quiet); status = format_string(format_find(ekg_status_label(u->status, "user_info_")), (u->first_name) ? u->first_name : u->display, u->descr); for (i = 0; i < strlen(status); i++) if (status[i] == 10) status[i] = '|'; groups = group_to_string(u->groups, 0, 1); ip_str = saprintf("%s:%s", inet_ntoa(u->ip), itoa(u->port)); printq("user_info_header", u->display, itoa(u->uin)); if (u->nickname && strcmp(u->nickname, u->display)) printq("user_info_nickname", u->nickname); if (u->first_name && strcmp(u->first_name, "") && u->last_name && u->last_name && strcmp(u->last_name, "")) printq("user_info_name", u->first_name, u->last_name); if (u->first_name && strcmp(u->first_name, "") && (!u->last_name || !strcmp(u->last_name, ""))) printq("user_info_name", u->first_name, ""); if ((!u->first_name || !strcmp(u->first_name, "")) && u->last_name && strcmp(u->last_name, "")) printq("user_info_name", u->last_name, ""); if (u->email) printq("user_info_email", u->email); printq("user_info_status", status); if (group_member(u, "__blocked")) printq("user_info_block", ((u->first_name) ? u->first_name : u->display)); if (group_member(u, "__offline")) printq("user_info_offline", ((u->first_name) ? u->first_name : u->display)); if (u->port == 2) printq("user_info_not_in_contacts"); if (u->port == 1) printq("user_info_firewalled"); if (u->ip.s_addr) printq("user_info_ip", ip_str); if ((u->protocol & GG_HAS_AUDIO_MASK)) printq("user_info_voip"); if ((u->protocol & 0x00ffffff)) { int v = u->protocol & 0x00ffffff; const char *ver = NULL; if (v < 0x0b) ver = "<= 4.0.x"; if (v >= 0x0f && v <= 0x10) ver = "4.5.x"; if (v == 0x11) ver = "4.6.x"; if (v >= 0x14 && v <= 0x15) ver = "4.8.x"; if (v >= 0x16 && v <= 0x17) ver = "4.9.x"; if (v >= 0x18 && v <= 0x1b) ver = "5.0.x"; if (v >= 0x1c && v <= 0x1e) ver = "5.7"; if (v == 0x20) ver = "6.0 (build 129 lub nowszy)" ; if (v == 0x21) ver = "6.0 (build 133 lub nowszy)"; if (v == 0x22) ver = "6.0 (build 140 lub nowszy)"; if (v == 0x24) ver = "6.1 (build 155 lub nowszy) lub 7.6 (build 1359 lub nowszy)"; if (v == 0x25) ver = "7.0 (build 1 lub nowszy)"; if (v == 0x26) ver = "7.0 (build 20 lub nowszy)"; if (v == 0x27) ver = "7.0 (build 22 lub nowszy)"; if (v == 0x28) ver = "7.5.0 (build 2201 lub nowszy)"; if (v == 0x29) ver = "7.6 (build 1688 lub nowszy)"; if (v == 0x2a) ver = "7.7 (build 3315 lub nowszy)"; if (v == 0x2d) ver = "Nowe Gadu-Gadu (build 4881 lub nowszy)"; if (v == 0x2e) ver = "Nowe Gadu-Gadu (build 8283 lub nowszy)"; if (ver) printq("user_info_version", ver); else { char *tmp = saprintf("nieznana (%#.2x)", v); printq("user_info_version", tmp); xfree(tmp); } } if (u->mobile && strcmp(u->mobile, "")) printq("user_info_mobile", u->mobile); if (strcmp(groups, "")) printq("user_info_groups", groups); if (GG_S_NA(u->status)) { char buf[100]; struct tm *last_seen_time; if (u->last_seen) { last_seen_time = localtime(&(u->last_seen)); strftime(buf, sizeof(buf), format_find("user_info_last_seen_time"), last_seen_time); printq("user_info_last_seen", buf); if (u->last_descr && strcmp(u->last_descr, "") && (!u->descr || strcmp(u->descr, u->last_descr))) printq("user_info_last_descr", u->last_descr); if (u->last_ip.s_addr) { char *tmp = saprintf("%s:%s", inet_ntoa(u->last_ip), itoa(u->last_port)); printq("user_info_last_ip", tmp); xfree(tmp); } } else printq("user_info_never_seen"); } printq("user_info_footer", u->display, itoa(u->uin)); xfree(ip_str); xfree(groups); xfree(status); if (params_null) params[0] = NULL; return 0; } #ifdef HAVE_REGEX_H /* list --regex */ if (params[0] && match_arg(params[0], 'r', "regex", 2)) { int rs, flags = REG_NOSUB; char errbuf[512]; regex_t reg; if (!params[1]) { printq("not_enough_params", name); return -1; } if (!(config_regex_flags & 1)) flags |= REG_EXTENDED; if (!(config_regex_flags & 2)) flags |= REG_ICASE; if ((rs = regcomp(®, params[1], flags))) goto err; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; int show = 0; if (!u->display || !u->uin) continue; rs = regexec(®, u->display, 0, NULL, 0); if (!rs) show = 1; else if (rs != REG_NOMATCH) goto err; if (!show) { rs = regexec(®, itoa(u->uin), 0, NULL, 0); if (!rs) show = 1; else if (rs != REG_NOMATCH) goto err; } if (!show) continue; tmp = ekg_status_label(u->status, "list_"); if (u->uin == config_uin && sess && sess->state == GG_STATE_CONNECTED && !ignored_check(config_uin)) tmp = ekg_status_label(config_status, "list_"); printq(tmp, format_user(u->uin), (u->first_name) ? u->first_name : u->display, inet_ntoa(u->ip), itoa(u->port), u->descr); count++; } if (!count) printq("regex_none"); regfree(®); return 0; err: regerror(rs, ®, errbuf, sizeof(errbuf)); printq("regex_error", errbuf); regfree(®); return -1; } #endif /* list --get */ if (params[0] && (match_arg(params[0], 'g', "get", 2) || match_arg(params[0], 'G', "get-config", 5))) { if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if (gg_userlist_request(sess, GG_USERLIST_GET, NULL) == -1) { printq("userlist_get_error", strerror(errno)); return -1; } userlist_get_config = (match_arg(params[0], 'G', "get-config", 5)); return 0; } /* list --clear */ if (params[0] && (match_arg(params[0], 'c', "clear", 2) || match_arg(params[0], 'C', "clear-config", 8))) { char *contacts = NULL; if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if (match_arg(params[0], 'c', "clear", 2)) { string_t s = string_init(contacts); char *vars = variable_digest(); int i, count; count = strlen(vars) / 120; if (strlen(vars) % 120 != 0) count++; for (i = 0; i < count; i++) { string_append(s, "__config"); string_append(s, itoa(i)); string_append_c(s, ';'); for (j = 0; j < 5; j++) { char *tmp; if (i * 120 + j * 24 < strlen(vars)) tmp = xstrmid(vars, i * 120 + j * 24, 24); else tmp = xstrdup(""); string_append(s, tmp); string_append_c(s, ';'); xfree(tmp); } string_append(s, itoa(rand() % 3000000 + 10000)); string_append(s, "\r\n"); } xfree(vars); xfree(contacts); contacts = string_free(s, 0); } else contacts = xstrdup(""); if (gg_userlist_request(sess, GG_USERLIST_PUT, NULL) == -1) { printq("userlist_clear_error", strerror(errno)); xfree(contacts); return -1; } userlist_put_config = (match_arg(params[0], 'c', "clear", 2)) ? 2 : 3; xfree(contacts); return 0; } /* list --put */ if (params[0] && (match_arg(params[0], 'p', "put", 2) || match_arg(params[0], 'P', "put-config", 5))) { char *contacts; if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } contacts = userlist_dump(); iso_to_cp((unsigned char *) contacts); if (match_arg(params[0], 'P', "put-config", 5)) { string_t s = string_init(contacts); char *vars = variable_digest(); int i, count; count = strlen(vars) / 120; if (strlen(vars) % 120 != 0) count++; for (i = 0; i < count; i++) { string_append(s, "__config"); string_append(s, itoa(i)); string_append_c(s, ';'); for (j = 0; j < 5; j++) { char *tmp; if (i * 120 + j * 24 < strlen(vars)) tmp = xstrmid(vars, i * 120 + j * 24, 24); else tmp = xstrdup(""); string_append(s, tmp); string_append_c(s, ';'); xfree(tmp); } string_append(s, itoa(rand() % 3000000 + 10000)); string_append(s, "\r\n"); } xfree(vars); xfree(contacts); contacts = string_free(s, 0); } if (gg_userlist_request(sess, GG_USERLIST_PUT, contacts) == -1) { printq("userlist_put_error", strerror(errno)); xfree(contacts); return -1; } userlist_put_config = (match_arg(params[0], 'P', "put-config", 5)); xfree(contacts); return -1; } /* list --active | --busy | --inactive | --invisible | --description | --member | --blocked | --offline */ for (j = 0; params[j]; j++) { int i; argv = array_make(params[j], " \t", 0, 1, 1); for (i = 0; argv[i]; i++) { if (match_arg(argv[i], 'a', "active", 2)) { show_all = 0; show_active = 1; } if (match_arg(argv[i], 'i', "inactive", 2) || match_arg(argv[i], 'n', "notavail", 2)) { show_all = 0; show_inactive = 1; } if (match_arg(argv[i], 'b', "busy", 2)) { show_all = 0; show_busy = 1; } if (match_arg(argv[i], 'f', "ffc", 2)) { show_all = 0; show_ffc = 1; } if (match_arg(argv[i], 'D', "dnd", 2)) { show_all = 0; show_dnd = 1; } if (match_arg(argv[i], 'I', "invisible", 2)) { show_all = 0; show_invisible = 1; } if (match_arg(argv[i], 'B', "blocked", 2)) { show_all = 0; show_blocked = 1; } if (match_arg(argv[i], 'o', "offline", 2)) { show_all = 0; show_offline = 1; } if (match_arg(argv[i], 'm', "member", 2)) { if (j && argv[i+1]) { int off = 0; if (argv[i+1][0] == '!') { show_group_inverted = 1; off++; } off = (argv[i+1][off] == '@' && strlen(argv[i+1]) > 1) ? off + 1 : off; show_group = xstrdup(argv[i+1] + off); } else if (params[i+1]) { char **tmp = array_make(params[i+1], " \t", 0, 1, 1); int off = 0; if (params[i+1][0] == '!') { show_group_inverted = 1; off++; } off = (params[i+1][off] == '@' && strlen(params[i+1]) > 1) ? off + 1 : off; show_group = xstrdup(tmp[0] + off); array_free(tmp); } } if (match_arg(argv[i], 'd', "description", 2)) show_descr = 1; } array_free(argv); } for (l = userlist; l; l = l->next) { struct userlist *u = l->data; int show; if (!u->display || !u->uin) continue; tmp = ekg_status_label(u->status, "list_"); if (u->uin == config_uin && sess && sess->state == GG_STATE_CONNECTED && !ignored_check(config_uin)) tmp = ekg_status_label(config_status, "list_"); show = show_all; if (show_busy && GG_S_B(u->status) && !GG_S_DD(u->status)) show = 1; if (show_ffc && GG_S_FF(u->status)) show = 1; if (show_dnd && GG_S_DD(u->status)) show = 1; if (show_active && GG_S_A(u->status) && !GG_S_FF(u->status)) show = 1; if (show_inactive && GG_S_NA(u->status)) show = 1; if (show_invisible && GG_S_I(u->status)) show = 1; if (show_blocked && GG_S_BL(u->status)) show = 1; if (show_descr && !GG_S_D(u->status)) show = 0; if (show_group && (show_group_inverted == group_member(u, show_group))) show = 0; if (show_offline && group_member(u, "__offline")) show = 1; if (show) { printq(tmp, format_user(u->uin), (u->first_name) ? u->first_name : u->display, inet_ntoa(u->ip), itoa(u->port), u->descr); count++; } } if (!count && !(show_descr || show_group) && show_all) printq("list_empty"); xfree(show_group); return 0; } /* * msg_all_wrapper() * * rozsyła wiadomość do wszystkich rozmówców w oknach. */ static void msg_all_wrapper(int chat, const char *msg, int quiet) { char **nicks = NULL; int i; ui_event("command", quiet, "query-nicks", &nicks, NULL); if (!nicks) return; for (i = 0; nicks[i]; i++) { const char *params[] = { nicks[i], msg, NULL }; cmd_msg(((chat) ? "chat" : "msg"), params, NULL, quiet); } array_free(nicks); } COMMAND(cmd_msg) { struct userlist *u; char **nicks = NULL, *nick = NULL, **p = NULL, *add_send = NULL; unsigned char *msg = NULL, *raw_msg = NULL, *format = NULL; uin_t uin; int count, valid = 0, secure = 0, msg_seq, formatlen = 0, conference = 0; int chat = (config_msg_as_chat == 2) ? 1 : !strcasecmp(name, "chat"); int chatsend = config_msg_as_chat ? 1 : !strcasecmp(name, "chat"); if (!params[0] || !params[1]) { printq("not_enough_params", name); return -1; } if (!strcmp(params[0], "*")) { msg_all_wrapper(chat, params[1], quiet); return 0; } if (config_auto_back == 1 && GG_S_B(config_status) && in_auto_away) change_status(GG_STATUS_AVAIL, NULL, 1); if (strlen(params[1]) > 1989) printq("message_too_long"); msg = (unsigned char *) xstrmid(params[1], 0, 1989); nick = xstrdup(params[0]); #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(msg_own, "(ss)", nick, msg) { char *a, *b; PYTHON_HANDLE_RESULT("ss", &a, &b) { xfree(nick); nick = xstrdup(a); xfree(msg); msg = xstrdup(b); } } PYTHON_HANDLE_FOOTER() if (!python_handle_result) { xfree(nick); xfree(msg); return -1; } #endif if ((*nick == '@' || strchr(nick, ',')) && chat && config_auto_conference) { struct conference *c = conference_create(nick); list_t l; if (c) { conference = 1; xfree(nick); nick = xstrdup(c->name); for (l = c->recipients; l; l = l->next) array_add(&nicks, xstrdup(itoa(*((uin_t *) (l->data))))); add_send = xstrdup(c->name); } } else if (*nick == '#') { struct conference *c = conference_find(nick); list_t l; if (!c) { printq("conferences_noexist", nick); xfree(nick); xfree(msg); return -1; } conference = 1; for (l = c->recipients; l; l = l->next) array_add(&nicks, xstrdup(itoa(*((uin_t *) (l->data))))); add_send = xstrdup(c->name); } else { char **tmp = array_make(nick, ",", 0, 0, 0); int i; for (i = 0; tmp[i]; i++) { int count = 0; list_t l; if (tmp[i][0] != '@') { if (!array_contains(nicks, tmp[i], 0)) array_add(&nicks, xstrdup(tmp[i])); continue; } for (l = userlist; l; l = l->next) { struct userlist *u = l->data; list_t m; for (m = u->groups; m; m = m->next) { struct group *g = m->data; if (!strcasecmp(g->name, tmp[i] + 1)) { if (u->display && !array_contains(nicks, u->display, 0)) array_add(&nicks, xstrdup(u->display)); count++; } } } if (!count) printq("group_empty", tmp[i] + 1); } array_free(tmp); } if (!nicks) { xfree(nick); xfree(msg); return 0; } /* analizę tekstu zrobimy w osobnym bloku dla porządku */ { unsigned char attr = 0, last_attr = 0; const unsigned char *p = msg, *end = p + strlen((char *) p); int msglen = 0; unsigned char rgb[3], last_rgb[3]; for (p = msg; p < end; ) { if (*p == 18) { /* Ctrl-R */ p++; if (xisdigit(*p)) { int num = atoi((char *) p); if (num < 0 || num > 15) num = 0; p++; if (xisdigit(*p)) p++; rgb[0] = default_color_map[num].r; rgb[1] = default_color_map[num].g; rgb[2] = default_color_map[num].b; attr |= GG_FONT_COLOR; } else attr &= ~GG_FONT_COLOR; continue; } if (*p == 2) { /* Ctrl-B */ attr ^= GG_FONT_BOLD; p++; continue; } if (*p == 20) { /* Ctrl-T */ attr ^= GG_FONT_ITALIC; p++; continue; } if (*p == 31) { /* Ctrl-_ */ attr ^= GG_FONT_UNDERLINE; p++; continue; } if (*p < 32 && *p != 13 && *p != 10 && *p != 9) { p++; continue; } if (attr != last_attr || ((attr & GG_FONT_COLOR) && memcmp(last_rgb, rgb, sizeof(rgb)))) { int color = 0; memcpy(last_rgb, rgb, sizeof(rgb)); if (!format) { format = xmalloc(3); format[0] = 2; formatlen = 3; } if ((attr & GG_FONT_COLOR)) color = 1; if ((last_attr & GG_FONT_COLOR) && !(attr & GG_FONT_COLOR)) { color = 1; memset(rgb, 0, 3); } format = xrealloc(format, formatlen + ((color) ? 6 : 3)); format[formatlen] = (msglen & 255); format[formatlen + 1] = ((msglen >> 8) & 255); format[formatlen + 2] = attr | ((color) ? GG_FONT_COLOR : 0); if (color) { memcpy(format + formatlen + 3, rgb, 3); formatlen += 6; } else formatlen += 3; last_attr = attr; } msg[msglen++] = *p; p++; } msg[msglen] = 0; if (format && formatlen) { format[1] = (formatlen - 3) & 255; format[2] = ((formatlen - 3) >> 8) & 255; } } raw_msg = (unsigned char *) xstrdup((char *) msg); iso_to_cp(msg); count = array_count(nicks); for (p = nicks; *p; p++) { if (!strcmp(*p, "")) continue; if (!(uin = get_uin(*p))) { printq("user_not_found", *p); continue; } u = userlist_find(uin, NULL); put_log(uin, "%s,%ld,%s,%s,%s\n", ((chatsend) ? "chatsend" : "msgsend"), uin, ((u && u->display) ? u->display : ""), log_timestamp(time(NULL)), raw_msg); if (config_last & 4) last_add(1, uin, time(NULL), 0, (char *) raw_msg); secure = 0; if (!conference) { unsigned char *__msg = (unsigned char *) xstrdup((char *) msg); #ifdef HAVE_OPENSSL int ret = 0; if ((config_encryption == 1 || config_encryption == 3) && (ret = msg_encrypt(uin, &__msg)) > 0) secure = 1; if (ret == 2) printq("message_too_long"); #endif if (sess) msg_seq = gg_send_message_richtext(sess, (chatsend) ? GG_CLASS_CHAT : GG_CLASS_MSG, uin, __msg, format, formatlen); else msg_seq = -1; msg_queue_add(((chatsend) ? GG_CLASS_CHAT : GG_CLASS_MSG), msg_seq, 1, &uin, raw_msg, secure, format, formatlen); valid++; xfree(__msg); } } if (conference) { uin_t *uins = xmalloc(count * sizeof(uin_t)); int realcount = 0; for (p = nicks; *p; p++) if ((uin = get_uin(*p))) uins[realcount++] = uin; if (sess) msg_seq = gg_send_message_confer_richtext(sess, GG_CLASS_CHAT, realcount, uins, msg, format, formatlen); else msg_seq = -1; msg_queue_add(((chatsend) ? GG_CLASS_CHAT : GG_CLASS_MSG), msg_seq, count, uins, raw_msg, 0, format, formatlen); valid++; xfree(uins); } if (!add_send) add_send = xstrdup(nick); if (valid) add_send_nick(add_send); xfree(add_send); if (valid && config_display_sent) { struct gg_event e; struct userlist u; memset(&e, 0, sizeof(e)); e.type = GG_EVENT_MSG; e.event.msg.sender = config_uin; e.event.msg.message = (unsigned char *) xstrdup((char *) raw_msg); e.event.msg.time = time(NULL); e.event.msg.formats = (format) ? (format + 3) : NULL; e.event.msg.formats_length = (formatlen) ? (formatlen - 3) : 0; memset(&u, 0, sizeof(u)); u.uin = 0; u.display = xstrdup(nick); if (!quiet) print_message(&e, &u, (chat) ? 3 : 4, secure); xfree(e.event.msg.message); xfree(u.display); } if (valid && (!sess || sess->state != GG_STATE_CONNECTED)) printq("not_connected_msg_queued"); xfree(msg); xfree(raw_msg); xfree(format); xfree(nick); array_free(nicks); unidle(); return 0; } COMMAND(cmd_save) { last_save = time(NULL); if (!userlist_write(0) && !config_write(params[0])) { printq("saved"); config_changed = 0; config_last_sysmsg_changed = 0; } else { printq("error_saving"); return -1; } return 0; } COMMAND(cmd_set) { const char *arg = NULL, *val = NULL; int unset = 0, show_all = 0, res = 0; char *value = NULL; list_t l; if (match_arg(params[0], 'a', "all", 1)) { show_all = 1; arg = params[1]; if (arg) val = params[2]; } else { arg = params[0]; if (arg) val = params[1]; } if (arg && arg[0] == '-') { unset = 1; arg++; } if (arg && val) { char **tmp = array_make(val, "", 0, 0, 1); value = xstrdup(tmp[0]); array_free(tmp); } if ((!arg || !val) && !unset) { int displayed = 0; for (l = variables; l; l = l->next) { struct variable *v = l->data; if ((!arg || ((config_irssi_set_mode == 0 || !strcmp(name, "set-show")) ? !strcasecmp(arg, v->name) : strstr(v->name, arg) != NULL)) && (v->display != 2 || strcmp(name, "set"))) { char *string = *(char**)(v->ptr); int value = *(int*)(v->ptr); if (!show_all && !arg && v->dyndisplay && !(*v->dyndisplay)(v->name)) continue; if (!v->display) { printq("variable", v->name, "(...)"); displayed = 1; continue; } if (v->type == VAR_STR) { char *tmp = (string) ? saprintf("\"%s\"", string) : "(none)"; printq("variable", v->name, tmp); if (string) xfree(tmp); } if (v->type == VAR_BOOL) printq("variable", v->name, (value) ? "1 (on)" : "0 (off)"); if ((v->type == VAR_INT || v->type == VAR_MAP) && !v->map) printq("variable", v->name, itoa(value)); if (v->type == VAR_INT && v->map) { char *tmp = NULL; int i; for (i = 0; v->map[i].label; i++) if (v->map[i].value == value) { tmp = saprintf("%d (%s)", value, v->map[i].label); break; } if (!tmp) tmp = saprintf("%d", value); printq("variable", v->name, tmp); xfree(tmp); } if (v->type == VAR_MAP && v->map) { string_t s = string_init(itoa(value)); int i, first = 1; for (i = 0; v->map[i].label; i++) { if ((value & v->map[i].value) || (!value && !v->map[i].value)) { string_append(s, (first) ? " (" : ","); first = 0; string_append(s, v->map[i].label); } } if (!first) string_append_c(s, ')'); printq("variable", v->name, s->str); string_free(s, 1); } displayed = 1; } } if (!displayed && params[0]) { printq("variable_not_found", params[0]); return -1; } } else { theme_cache_reset(); switch (variable_set(arg, (unset) ? NULL : value, 0)) { case 0: { const char *my_params[2] = { (!unset) ? params[0] : params[0] + 1, NULL }; cmd_set("set-show", my_params, NULL, quiet); config_changed = 1; last_save = time(NULL); break; } case -1: printq("variable_not_found", arg); res = -1; break; case -2: printq("variable_invalid", arg); res = -1; break; } } xfree(value); return res; } COMMAND(cmd_sms) { struct userlist *u; const char *number = NULL; if (!params[0] || !params[1]) { printq("not_enough_params", name); return -1; } if (!config_sms_app) { printq("var_not_set", "sms_send_app"); return -1; } if ((u = userlist_find(get_uin(params[0]), NULL))) { if (!u->mobile || !strcmp(u->mobile, "")) { printq("sms_unknown", format_user(u->uin)); return -1; } number = u->mobile; } else { number = params[0]; u = userlist_find_mobile(number); } if (send_sms(number, params[1], quiet) == -1) { printq("sms_error", strerror(errno)); return -1; } if (u) { if ((config_log & 2)) { put_log(u->uin, "smssend,%s,%s,%s\n", number, log_timestamp(time(NULL)), params[1]); } else put_log(u->uin, "smssend,%s,%s,%s,%s,%ld\n", number, log_timestamp(time(NULL)), params[1], u->display ? u->display : "", u->uin); } else put_log(0, "smssend,%s,%s,%s\n", number, log_timestamp(time(NULL)), params[1]); return 0; } COMMAND(cmd_quit) { char *tmp = NULL; if (!params[0]) { if (config_random_reason & 2) { tmp = random_line(prepare_path("quit.reasons", 0)); if (!tmp && config_quit_reason) tmp = xstrdup(config_quit_reason); } else if (config_quit_reason) tmp = xstrdup(config_quit_reason); } else tmp = xstrdup(params[0]); if (!tmp && config_keep_reason && config_reason) tmp = xstrdup(config_reason); xfree(config_reason); config_reason = NULL; if (params[0] && !strcmp(params[0], "-")) { xfree(tmp); tmp = NULL; config_status = ekg_hide_descr_status(config_status); } if (config_keep_reason) config_reason = xstrdup(tmp); if (!quit_message_send) { if (tmp) { char *r1, *r2; r1 = xstrmid(tmp, 0, GG_STATUS_DESCR_MAXSIZE); r2 = xstrmid(tmp, GG_STATUS_DESCR_MAXSIZE, -1); printq("quit_descr", r1, r2); xfree(r1); xfree(r2); } else printq("quit"); quit_message_send = 1; } ekg_logoff(sess, tmp); xfree(tmp); ui_event("disconnected", NULL); /* nie wychodzimy tutaj, żeby command_exec() miało szansę zwolnić * używaną przez siebie pamięć. */ quit_command = 1; return 0; } COMMAND(cmd_dcc) { struct transfer t; list_t l; uin_t uin; if (!params[0] || !strncasecmp(params[0], "li", 2)) { /* list */ int empty = 1, passed = 0; for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if ((!t->dcc && !t->dcc7) || (t->dcc && !t->dcc->established) || (t->dcc7 && !t->dcc7->established)) { empty = 0; if (!passed) printq("dcc_show_pending_header"); passed++; switch (t->type) { case GG_SESSION_DCC_SEND: case GG_SESSION_DCC7_SEND: printq("dcc_show_pending_send", itoa(t->id), format_user(t->uin), t->filename); break; case GG_SESSION_DCC_GET: case GG_SESSION_DCC7_GET: printq("dcc_show_pending_get", itoa(t->id), format_user(t->uin), t->filename); break; case GG_SESSION_DCC_VOICE: case GG_SESSION_DCC7_VOICE: printq("dcc_show_pending_voice", itoa(t->id), format_user(t->uin)); } } } passed = 0; for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if ((t->dcc && t->dcc->established) || (t->dcc7 && t->dcc7->established)) { int eta_m = 0, eta_s = 0, speed_kb = 0; unsigned int size = 0, offset = 0; if (t->dcc) { size = t->dcc->file_info.size; offset = t->dcc->offset; } if (t->dcc7) { size = t->dcc7->size; offset = t->dcc7->offset; } if (!size) size = 1; // dzielimy przez size empty = 0; if (!passed) printq("dcc_show_active_header"); passed++; if (t->start) { time_t cur, elapsed = 0, eta = 0; int speed = 0; cur = time(NULL); if (cur != -1 && cur >= t->start) elapsed = cur - t->start; if (elapsed) { speed = offset / elapsed; if (offset && offset <= size) eta = (size - offset) * elapsed / offset; } /* teraz elapsed zawiera czas, który upłynął * od rozpoczęcia transferu, speed prędkość * w bajtach na sekundę a eta estymowany * czas, który pozostał do przesłania całego * pliku. zamieniamy na bardziej rozsądne * wartości (prędkość w kB/s a pozostały * czas w minutach i sekundach). */ speed_kb = speed / 1024; eta_m = eta / 60; eta_s = eta - eta_m * 60; } switch (t->type) { case GG_SESSION_DCC_SEND: case GG_SESSION_DCC7_SEND: if (speed_kb || eta_m || eta_s) { if (eta_m) printq("dcc_show_active_send_speed_ms", itoa(t->id), format_user(t->uin), t->filename, itoa(offset), itoa(size), itoa((float)100*((float)offset/(float)size)), itoa(speed_kb), itoa(eta_m), itoa(eta_s)); else printq("dcc_show_active_send_speed_s", itoa(t->id), format_user(t->uin), t->filename, itoa(offset), itoa(size), itoa((float)100*((float)offset/(float)size)), itoa(speed_kb), itoa(eta_s)); } else printq("dcc_show_active_send", itoa(t->id), format_user(t->uin), t->filename, itoa(offset), itoa(size), itoa((float)100*((float)offset/(float)size))); break; case GG_SESSION_DCC_GET: case GG_SESSION_DCC7_GET: if (speed_kb || eta_m || eta_s) { if (eta_m) printq("dcc_show_active_get_speed_ms", itoa(t->id), format_user(t->uin), t->filename, itoa(offset), itoa(size), itoa((float)100*((float)offset/(float)size)), itoa(speed_kb), itoa(eta_m), itoa(eta_s)); else printq("dcc_show_active_get_speed_s", itoa(t->id), format_user(t->uin), t->filename, itoa(offset), itoa(size), itoa((float)100*((float)offset/(float)size)), itoa(speed_kb), itoa(eta_s)); } else printq("dcc_show_active_get", itoa(t->id), format_user(t->uin), t->filename, itoa(offset), itoa(size), itoa((float)100*((float)offset/(float)size))); break; case GG_SESSION_DCC_VOICE: case GG_SESSION_DCC7_VOICE: printq("dcc_show_active_voice", itoa(t->id), format_user(t->uin)); } } } if (empty) printq("dcc_show_empty"); return 0; } if (!strncasecmp(params[0], "se", 2) || !strncasecmp(params[0], "rse", 3)) { /* send, rsend */ struct userlist *u; struct stat st; int fd; if (!params[1] || !params[2]) { printq("not_enough_params", name); return -1; } uin = get_uin(params[1]); if (!(u = userlist_find(uin, params[1]))) { printq("user_not_found", params[1]); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if (!(GG_S_A(u->status) || GG_S_B(u->status)) && !(ignored_check(uin) & IGNORE_STATUS)) { printq("dcc_user_not_avail", format_user(u->uin), (u->first_name) ? u->first_name : u->display); return -1; } if ((u->protocol < 0x2a && !u->ip.s_addr && params[0][0] != 'r') || (u->protocol >= 0x2a && !u->port)) { printq("dcc_user_aint_dcc", format_user(u->uin)); return -1; } if ((fd = open(params[2], O_RDONLY)) == -1) { printq("dcc_open_error", params[2], strerror(errno)); return -1; } close(fd); if (!stat(params[2], &st) && S_ISDIR(st.st_mode)) { printq("dcc_open_error", params[2], strerror(EISDIR)); return -1; } t.uin = uin; t.id = transfer_id(); t.type = GG_SESSION_DCC_SEND; t.filename = xstrdup(params[2]); t.start = time(NULL); t.dcc = NULL; if (t.start == -1) t.start = 0; if (u->protocol < 0x2a) { if (u->port < 10 || !strncasecmp(params[0], "rse", 3)) { /* nie możemy się z nim połączyć, więc on spróbuje */ gg_dcc_request(sess, uin); } else { struct gg_dcc *d; char *remote; if (!(d = gg_dcc_send_file(u->ip.s_addr, u->port, config_uin, uin))) { printq("dcc_error", strerror(errno)); return -1; } remote = xstrdup(params[2]); iso_to_cp((unsigned char *) remote); if (gg_dcc_fill_file_info2(d, remote, params[2]) == -1) { printq("dcc_open_error", params[2], strerror(errno)); gg_free_dcc(d); xfree(remote); return -1; } xfree(remote); list_add(&watches, d, 0); t.dcc = d; } } else { struct gg_dcc7 *d; char *remote; remote = xstrdup(t.filename); iso_to_cp((unsigned char *) remote); if (!(d = gg_dcc7_send_file(sess, u->uin, t.filename, remote, NULL))) { printq("dcc_error", strerror(errno)); return -1; } list_add(&watches, d, 0); t.dcc7 = d; } list_add(&transfers, &t, sizeof(t)); return 0; } if (params[0][0] == 'v' || !strncasecmp(params[0], "rvo", 3)) { /* voice, rvoice */ #ifdef HAVE_VOIP struct userlist *u = NULL; struct transfer *t, tt; if (!params[1]) { printq("not_enough_params", name); return -1; } /* sprawdzamy najpierw przychodzące połączenia */ for (t = NULL, l = transfers; l; l = l->next) { struct transfer *f = l->data; struct userlist *u; f = l->data; if (!f->dcc || !f->dcc->incoming || f->type != GG_SESSION_DCC_VOICE) continue; if (params[1][0] == '#' && atoi(params[1] + 1) == f->id) { t = f; break; } if (t && (u = userlist_find(t->uin, NULL))) { if (!strcasecmp(params[1], itoa(u->uin)) || (u->display && !strcasecmp(params[1], u->display))) { t = f; break; } } } if (t) { if ((u = userlist_find(t->uin, NULL))) t->protocol = u->protocol; list_add(&watches, t->dcc, 0); voice_open(); return 0; } /* sprawdź, czy już nie wołano o rozmowę głosową */ #if 0 for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if (t->type == GG_SESSION_DCC_VOICE) { printq("dcc_voice_running"); return 0; } } for (l = watches; l; l = l->next) { struct gg_session *s = l->data; if (s->type == GG_SESSION_DCC_VOICE) { printq("dcc_voice_running"); return 0; } } #endif /* jeśli nie było, to próbujemy sami zainicjować */ uin = get_uin(params[1]); if (!(u = userlist_find(uin, params[1]))) { printq("user_not_found", params[1]); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if (!(GG_S_A(u->status) || GG_S_B(u->status)) && !(ignored_check(uin) & IGNORE_STATUS)) { printq("dcc_user_not_avail", format_user(u->uin), (u->first_name) ? u->first_name : u->display); return -1; } if (!u->ip.s_addr) { printq("dcc_user_aint_dcc", format_user(u->uin)); return -1; } memset(&tt, 0, sizeof(tt)); tt.uin = uin; tt.id = transfer_id(); tt.type = GG_SESSION_DCC_VOICE; tt.protocol = u->protocol; tt.start = time(NULL); if (tt.start == -1) tt.start = 0; if (u->port < 10 || !strncasecmp(params[0], "rvo", 3)) { /* nie możemy się z nim połączyć, więc on spróbuje */ gg_dcc_request(sess, uin); } else { struct gg_dcc *d; if (!(d = gg_dcc_voice_chat(u->ip.s_addr, u->port, config_uin, uin))) { printq("dcc_error", strerror(errno)); return -1; } list_add(&watches, d, 0); tt.dcc = d; } list_add(&transfers, &tt, sizeof(tt)); voice_open(); #else printq("dcc_voice_unsupported"); #endif return -1; } if (!strncasecmp(params[0], "g", 1) || !strncasecmp(params[0], "re", 2)) { /* get */ struct transfer *t = NULL; unsigned char *path, *tmp; int fd; unsigned int offset = 0; for (l = transfers; l; l = l->next) { struct transfer *tt = l->data; struct userlist *u; if (!tt->dcc && !tt->dcc7) continue; if (tt->dcc && tt->type != GG_SESSION_DCC_GET) continue; if (tt->dcc7 && tt->type != GG_SESSION_DCC7_GET) continue; if (!tt->filename) continue; if (!params[1]) { if ((tt->dcc && tt->dcc->established) || (tt->dcc7 && tt->dcc7->established)) continue; t = tt; break; } if (params[1][0] == '#' && strlen(params[1]) > 1 && atoi(params[1] + 1) == tt->id) { t = tt; break; } if ((u = userlist_find(tt->uin, NULL))) { if ((tt->dcc && tt->dcc->established) || (tt->dcc7 && tt->dcc7->established)) continue; if (!strcasecmp(params[1], itoa(u->uin)) || (u->display && !strcasecmp(params[1], u->display))) { t = tt; break; } } } if (!t || (!t->dcc && !t->dcc7)) { printq("dcc_not_found", (params[1]) ? params[1] : ""); return -1; } for (l = watches; l; l = l->next) { struct gg_common *c = l->data; if ((c->type == GG_SESSION_DCC_GET && t->dcc == l->data) || (c->type == GG_SESSION_DCC7_GET && t->dcc7 == l->data)) { printq("dcc_receiving_already", t->filename, format_user(t->uin)); return -1; } } t->start = time(NULL); if (t->start == -1) t->start = 0; if (config_dcc_dir) path = (unsigned char *) saprintf("%s/%s", config_dcc_dir, t->filename); else path = (unsigned char *) xstrdup(t->filename); tmp = unique_name(path); if (!tmp) { printq("dcc_get_cant_overwrite", path); if (t->dcc) gg_dcc_free(t->dcc); if (t->dcc7) gg_dcc7_free(t->dcc7); list_remove(&transfers, t, 1); xfree(path); return -1; } else if (tmp != path) { printq("dcc_get_backup_made", path, tmp); xfree(path); path = tmp; } if (params[0][0] == 'r') { fd = open((char *) path, O_WRONLY); if (fd != -1) offset = lseek(fd, 0, SEEK_END); } else { fd = open((char *) path, O_WRONLY | O_CREAT, config_files_mode_received); } if (fd == -1) { printq("dcc_get_cant_create", path); if (t->dcc) gg_dcc_free(t->dcc); if (t->dcc7) { gg_dcc7_reject(t->dcc7, GG_DCC7_REJECT_USER); gg_dcc7_free(t->dcc7); } list_remove(&transfers, t, 1); xfree(path); return -1; } if (t->dcc) { t->dcc->file_fd = fd; t->dcc->offset = offset; } if (t->dcc7) { t->dcc7->file_fd = fd; t->dcc7->offset = offset; { char buf[256]; sprintf(buf, "%p %d", t->dcc7, t->dcc7->file_fd); print("generic", buf); } } xfree(path); printq("dcc_get_getting", format_user(t->uin), t->filename); if (t->dcc) list_add(&watches, t->dcc, 0); if (t->dcc7) { gg_dcc7_accept(t->dcc7, offset); list_add(&watches, t->dcc7, 0); } return 0; } if (!strncasecmp(params[0], "c", 1)) { /* close */ struct transfer *t = NULL; uin_t uin; if (!params[1]) { printq("not_enough_params", name); return -1; } uin = get_uin(params[1]); for (l = transfers; l; l = l->next) { struct transfer *tt = l->data; if (params[1][0] == '#' && atoi(params[1] + 1) == tt->id) { t = tt; break; } if (uin && tt->uin == uin) { t = tt; break; } } if (!t) { printq("dcc_not_found", params[1]); return -1; } if (t->dcc7) { if (!t->dcc7->established) gg_dcc7_reject(t->dcc7, GG_DCC7_REJECT_USER); list_remove(&watches, t->dcc7, 0); gg_dcc7_free(t->dcc7); } if (t->dcc) { list_remove(&watches, t->dcc, 0); gg_dcc_free(t->dcc); } #ifdef HAVE_VOIP if (t->type == GG_SESSION_DCC_VOICE || t->type == GG_SESSION_DCC7_VOICE) voice_close(); #endif uin = t->uin; if (t->filename) xfree(t->filename); list_remove(&transfers, t, 1); printq("dcc_close", format_user(uin)); return 0; } printq("invalid_params", name); return -1; } COMMAND(cmd_version) { char buf[10]; snprintf(buf, sizeof(buf), "0x%.2x", GG_DEFAULT_PROTOCOL_VERSION); printq("ekg_version", VERSION, buf, GG_DEFAULT_CLIENT_VERSION, compile_time()); return 0; } #ifdef HAVE_OPENSSL COMMAND(cmd_key) { if (match_arg(params[0], 'g', "generate", 2)) { char *tmp, *tmp2; struct stat st; if (!config_uin) return -1; if (mkdir(prepare_path("keys", 1), 0700) && errno != EEXIST) { printq("key_generating_error", strerror(errno)); return -1; } tmp = saprintf("%s/%d.pem", prepare_path("keys", 0), config_uin); tmp2 = saprintf("%s/private.pem", prepare_path("keys", 0)); if (!stat(tmp, &st) && !stat(tmp2, &st)) { printq("key_private_exist"); xfree(tmp); xfree(tmp2); return -1; } xfree(tmp); xfree(tmp2); printq("key_generating"); if (sim_key_generate(config_uin)) { printq("key_generating_error", "sim_key_generate()"); return -1; } printq("key_generating_success"); return 0; } if (match_arg(params[0], 's', "send", 2)) { string_t s = string_init(NULL); char *tmp, buf[128]; uin_t uin; FILE *f; if (!params[1]) { printq("not_enough_params", name); return -1; } if (!(uin = get_uin(params[1]))) { printq("user_not_found", params[1]); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } tmp = saprintf("%s/%d.pem", prepare_path("keys", 0), config_uin); f = fopen(tmp, "r"); xfree(tmp); if (!f) { printq("key_public_not_found", format_user(config_uin)); return -1; } while (fgets(buf, sizeof(buf), f)) string_append(s, buf); fclose(f); if (gg_send_message(sess, GG_CLASS_MSG, uin, (unsigned char *) s->str) == -1) { printq("key_send_error"); string_free(s, 1); return -1; } printq("key_send_success", format_user(uin)); string_free(s, 1); return 0; } if (match_arg(params[0], 'd', "delete", 2)) { char *tmp; uin_t uin; if (!params[1]) { printq("not_enough_params", name); return -1; } if (!(uin = get_uin(params[1]))) { printq("user_not_found", params[1]); return -1; } if (uin == config_uin) { char *tmp = saprintf("%s/private.pem", prepare_path("keys", 0)); unlink(tmp); xfree(tmp); } tmp = saprintf("%s/%d.pem", prepare_path("keys", 0), uin); if (unlink(tmp)) printq("key_public_not_found", format_user(uin)); else printq("key_public_deleted", format_user(uin)); xfree(tmp); return 0; } if (!params[0] || match_arg(params[0], 'l', "list", 2) || params[0][0] != '-') { DIR *dir; struct dirent *d; int count = 0, list_uin = 0; const char *path = prepare_path("keys", 0); const char *x = NULL; if (!(dir = opendir(path))) { printq("key_public_noexist"); return 0; } if (params[0] && params[0][0] != '-') x = params[0]; else if (params[0] && match_arg(params[0], 'l', "list", 2)) x = params[1]; if (x && !(list_uin = get_uin(x))) { printq("user_not_found", x); closedir(dir); return -1; } while ((d = readdir(dir))) { struct stat st; char *name = saprintf("%s/%s", path, d->d_name); struct tm *tm; const char *tmp; if ((tmp = strstr(d->d_name, ".pem")) && !tmp[4] && !stat(name, &st) && S_ISREG(st.st_mode)) { int uin = atoi(d->d_name); if (list_uin && uin != list_uin) continue; if (uin) { char *fp = sim_key_fingerprint(uin); char ts[100]; tm = localtime(&st.st_mtime); strftime(ts, sizeof(ts), format_find("key_list_timestamp"), tm); print("key_list", format_user(uin), (fp) ? fp : "", ts); count++; xfree(fp); } } xfree(name); } closedir(dir); if (!count) printq("key_public_noexist"); return 0; } printq("invalid_params", name); return -1; } #endif COMMAND(cmd_token) { struct gg_http *h; if (!(h = gg_token(1))) { printq("token_failed", strerror(errno)); return -1; } list_add(&watches, h, 0); return 0; } COMMAND(cmd_test_segv) { char *foo = NULL; *foo = 'A'; return 0; } COMMAND(cmd_test_hexmsg) { int size = 0, i, j; char *buf; if (!params[0] || !params[1]) { printq("not_enough_params", name); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } for (i = 0; params[1][i]; i++) { if (xisxdigit(params[1][i])) size++; } size = size / 2; buf = xmalloc(size); memset(buf, 0, size); for (i = 0, j = 0; params[1][i]; i++) { char ch = tolower(params[1][i]), *hex = "0123456789abcdef"; if (!xisxdigit(ch)) continue; buf[j / 2] |= (int)(strchr(hex, ch) - hex); if ((j % 2) == 0) buf[j / 2] <<= 4; j++; } gg_send_message_ctcp(sess, GG_CLASS_MSG, get_uin(params[0]), (unsigned char *) buf, size); xfree(buf); return 0; } COMMAND(cmd_test_imagereq) { if (!params[0] || !params[1] || !params[2]) { printq("not_enough_params", name); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } return gg_image_request(sess, get_uin(params[0]), atoi(params[1]), strtoul(params[2], NULL, 16)); } COMMAND(cmd_test_imagesend) { int fd, size, res; char *image; if (!params[0] || !params[1]) { printq("not_enough_params", name); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if ((fd = open(params[1], O_RDONLY)) == -1) { printq("generic_error", strerror(errno)); return -1; } size = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); image = xmalloc(size); if (read(fd, image, size) < size) { printq("generic_error", strerror(errno)); return -1; } close(fd); res = gg_image_reply(sess, get_uin(params[0]), params[1], image, size); xfree(image); return res; } COMMAND(cmd_test_imagemsg) { char *image, *message = "", format[16] = { 0x02, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x09, 0x01, 0, 0, 0, 0, 0, 0, 0, 0 }; uint32_t tmp; int fd, size; if (!params[0] || !params[1]) { printq("not_enough_params", name); return -1; } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } if ((fd = open(params[1], O_RDONLY)) == -1) { printq("generic_error", strerror(errno)); return -1; } gg_debug(GG_DEBUG_MISC, "// sizeof(off_t) = %d\n", sizeof(off_t)); size = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); image = xmalloc(size); if (read(fd, image, size) < size) { printq("generic_error", strerror(errno)); close(fd); xfree(image); return -1; } close(fd); tmp = gg_crc32(0, (unsigned char *) image, size); gg_debug(GG_DEBUG_MISC, "// crc32 = 0x%.8x, size = %d\n", tmp, size); tmp = gg_fix32(tmp); memcpy(format + 12, &tmp, 4); tmp = gg_fix32(size); memcpy(format + 8, &tmp, 4); xfree(image); return gg_send_message_richtext(sess, GG_CLASS_CHAT, get_uin(params[0]), (unsigned char *) message, (unsigned char *) format, sizeof(format)); } COMMAND(cmd_test_resize) { ui_need_refresh = 1; return 0; } COMMAND(cmd_test_send) { struct gg_event *e = xmalloc(sizeof(struct gg_event)); if (!params[0] || !params[1]) { xfree(e); return -1; } memset(e, 0, sizeof(*e)); e->type = GG_EVENT_MSG; e->event.msg.sender = get_uin(params[0]); e->event.msg.message = (unsigned char *) xstrdup(params[1]); e->event.msg.msgclass = GG_CLASS_MSG; e->event.msg.time = time(NULL); handle_msg(e); event_free(); return 0; } COMMAND(cmd_test_addtab) { if (params[0]) add_send_nick(params[0]); return 0; } COMMAND(cmd_test_deltab) { if (params[0]) remove_send_nick(params[0]); return 0; } #ifndef GG_DEBUG_DISABLE COMMAND(cmd_test_debug) { if (params[0]) gg_debug(GG_DEBUG_MISC, "%s\n", params[0]); return 0; } COMMAND(cmd_test_debug_dump) { char *tmp = saprintf("Zapisałem debug do pliku debug.%d", (int) getpid()); debug_write_crash(); printq("generic", tmp); xfree(tmp); return 0; } #endif COMMAND(cmd_test_ping) { if (sess) gg_ping(sess); return 0; } COMMAND(cmd_test_watches) { list_t l; char buf[200], *type, *state, *check; int no = 0, queue = -1; for (l = watches; l; l = l->next, no++) { struct gg_common *s = l->data; switch (s->type) { case GG_SESSION_GG: type = "GG"; break; case GG_SESSION_HTTP: type = "HTTP"; break; case GG_SESSION_SEARCH: type = "SEARCH"; break; case GG_SESSION_REGISTER: type = "REGISTER"; break; case GG_SESSION_UNREGISTER: type = "UNREGISTER"; break; case GG_SESSION_REMIND: type = "REMIND"; break; case GG_SESSION_PASSWD: type = "PASSWD"; break; case GG_SESSION_DCC: type = "DCC"; break; case GG_SESSION_DCC_SOCKET: type = "DCC_SOCKET"; break; case GG_SESSION_DCC_SEND: type = "DCC_SEND"; break; case GG_SESSION_DCC_GET: type = "DCC_GET"; break; case GG_SESSION_DCC_VOICE: type = "DCC_VOICE"; break; case GG_SESSION_USERLIST_PUT: type = "USERLIST_PUT"; break; case GG_SESSION_USERLIST_GET: type = "USERLIST_GET"; break; case GG_SESSION_USER0: type = "USER0"; break; case GG_SESSION_USER1: type = "USER1"; break; case GG_SESSION_USER2: type = "USER2"; break; case GG_SESSION_USER3: type = "USER3"; break; case GG_SESSION_USER4: type = "USER4"; break; case GG_SESSION_USER5: type = "USER5"; break; case GG_SESSION_USER6: type = "USER6"; break; case GG_SESSION_USER7: type = "USER7"; break; default: type = "(unknown)"; break; } switch (s->check) { case GG_CHECK_READ: check = "R"; break; case GG_CHECK_WRITE: check = "W"; break; case GG_CHECK_READ | GG_CHECK_WRITE: check = "RW"; break; default: check = "?"; break; } switch (s->state) { /* gg_common */ case GG_STATE_IDLE: state = "IDLE"; break; case GG_STATE_RESOLVING: state = "RESOLVING"; break; case GG_STATE_CONNECTING: state = "CONNECTING"; break; case GG_STATE_READING_DATA: state = "READING_DATA"; break; case GG_STATE_ERROR: state = "ERROR"; break; /* gg_session */ case GG_STATE_CONNECTING_HUB: state = "CONNECTING_HUB"; break; case GG_STATE_CONNECTING_GG: state = "CONNECTING_GG"; break; case GG_STATE_READING_KEY: state = "READING_KEY"; break; case GG_STATE_READING_REPLY: state = "READING_REPLY"; break; case GG_STATE_CONNECTED: state = "CONNECTED"; break; /* gg_http */ case GG_STATE_SENDING_QUERY: state = "SENDING_QUERY"; break; case GG_STATE_READING_HEADER: state = "READING_HEADER"; break; case GG_STATE_PARSING: state = "PARSING"; break; case GG_STATE_DONE: state = "DONE"; break; /* gg_dcc */ case GG_STATE_LISTENING: state = "LISTENING"; break; case GG_STATE_READING_UIN_1: state = "READING_UIN_1"; break; case GG_STATE_READING_UIN_2: state = "READING_UIN_2"; break; case GG_STATE_SENDING_ACK: state = "SENDING_ACK"; break; case GG_STATE_READING_ACK: state = "READING_ACK"; break; case GG_STATE_READING_REQUEST: state = "READING_REQUEST"; break; case GG_STATE_SENDING_REQUEST: state = "SENDING_REQUEST"; break; case GG_STATE_SENDING_FILE_INFO: state = "SENDING_FILE_INFO"; break; case GG_STATE_READING_PRE_FILE_INFO: state = "READING_PRE_FILE_INFO"; break; case GG_STATE_READING_FILE_INFO: state = "READING_FILE_INFO"; break; case GG_STATE_SENDING_FILE_ACK: state = "SENDING_FILE_ACK"; break; case GG_STATE_READING_FILE_ACK: state = "READING_FILE_ACK"; break; case GG_STATE_SENDING_FILE_HEADER: state = "SENDING_FILE_HEADER"; break; case GG_STATE_READING_FILE_HEADER: state = "READING_FILE_HEADER"; break; case GG_STATE_GETTING_FILE: state = "SENDING_GETTING_FILE"; break; case GG_STATE_SENDING_FILE: state = "SENDING_SENDING_FILE"; break; case GG_STATE_READING_VOICE_ACK: state = "READING_VOICE_ACK"; break; case GG_STATE_READING_VOICE_HEADER: state = "READING_VOICE_HEADER"; break; case GG_STATE_READING_VOICE_SIZE: state = "READING_VOICE_SIZE"; break; case GG_STATE_READING_VOICE_DATA: state = "READING_VOICE_DATA"; break; case GG_STATE_SENDING_VOICE_ACK: state = "SENDING_VOICE_ACK"; break; case GG_STATE_SENDING_VOICE_REQUEST: state = "SENDING_VOICE_REQUEST"; break; case GG_STATE_READING_TYPE: state = "READING_TYPE"; break; default: state = "(unknown)"; break; } #ifdef FIONREAD ioctl(s->fd, FIONREAD, &queue); #endif snprintf(buf, sizeof(buf), "%d: type=%s, fd=%d, state=%s, check=%s, id=%d, timeout=%d, queue=%d", no, type, s->fd, state, check, s->id, s->timeout, queue); printq("generic", buf); } return 0; } #if 0 COMMAND(cmd_test_fds) { struct stat st; char buf[1000]; int i; for (i = 0; i < 2048; i++) { if (fstat(i, &st) == -1) continue; sprintf(buf, "%d: ", i); if (S_ISREG(st.st_mode)) sprintf(buf + strlen(buf), "file, inode %lu, size %lu", st.st_ino, st.st_size); if (S_ISSOCK(st.st_mode)) { struct sockaddr sa; struct sockaddr_un *sun = (struct sockaddr_un*) &sa; struct sockaddr_in *sin = (struct sockaddr_in*) &sa; int sa_len = sizeof(sa); if (getpeername(i, &sa, &sa_len) == -1) { strcat(buf, "socket, not connected"); } else { switch (sa.sa_family) { case AF_UNIX: strcat(buf, "socket, unix, "); strcat(buf, sun->sun_path); break; case AF_INET: strcat(buf, "socket, inet, "); strcat(buf, inet_ntoa(sin->sin_addr)); strcat(buf, ":"); strcat(buf, itoa(ntohs(sin->sin_port))); break; default: strcat(buf, "socket, "); strcat(buf, itoa(sa.sa_family)); } } } if (S_ISDIR(st.st_mode)) strcat(buf, "directory"); if (S_ISCHR(st.st_mode)) strcat(buf, "char"); if (S_ISBLK(st.st_mode)) strcat(buf, "block"); if (S_ISFIFO(st.st_mode)) strcat(buf, "fifo"); if (S_ISLNK(st.st_mode)) strcat(buf, "symlink"); printq("generic", buf); } return 0; } #endif COMMAND(cmd_beep) { ui_beep(); return 0; } #ifdef WITH_IOCTLD COMMAND(cmd_beeps_spk) { if (!params[0]) { printq("not_enough_params", name); return -1; } return ((ioctld_send(params[0], ACT_BEEPS_SPK, quiet) == -1) ? -1 : 0); } COMMAND(cmd_blink_leds) { if (!params[0]) { printq("not_enough_params", name); return -1; } return ((ioctld_send(params[0], ACT_BLINK_LEDS, quiet) == -1) ? -1 : 0); } #endif COMMAND(cmd_play) { if (!params[0]) { printq("not_enough_params", name); return -1; } if (!config_sound_app) { printq("var_not_set", "sound_app"); return -1; } return play_sound(params[0]); } COMMAND(cmd_say) { if (!params[0]) { printq("not_enough_params", name); return -1; } if (!config_speech_app) { printq("var_not_set", "speech_app"); return -1; } if (match_arg(params[0], 'c', "clear", 2)) { xfree(buffer_flush(BUFFER_SPEECH, NULL)); return 0; } return say_it(params[0]); } COMMAND(cmd_register) { struct gg_http *h; list_t l; if (name[0] == 'r') { char *passwd; if (registered_today) { printq("registered_today"); return -1; } if (!last_tokenid) { printq("token_missing"); return -1; } if (!params[0] || !params[1] || !params[2]) { printq("not_enough_params", name); return -1; } for (l = watches; l; l = l->next) { struct gg_common *s = l->data; if (s->type == GG_SESSION_REGISTER) { printq("register_pending"); return -1; } } passwd = xstrdup(params[1]); iso_to_cp((unsigned char *) passwd); if (!(h = gg_register3(params[0], passwd, last_tokenid, params[2], 1))) { xfree(passwd); printq("register_failed", strerror(errno)); return -1; } xfree(last_tokenid); last_tokenid = NULL; list_add(&watches, h, 0); reg_password = passwd; reg_email = xstrdup(params[0]); } else { uin_t uin = 0; if (!last_tokenid) { printq("token_missing"); return -1; } if (!params[0] || !params[1] || !params[2]) { printq("not_enough_params", name); return -1; } uin = get_uin(params[0]); if (uin <= 0) { printq("unregister_bad_uin", uin); return -1; } if (!(h = gg_unregister3(uin, params[1], last_tokenid, params[2], 1))) { printq("unregister_failed", strerror(errno)); return -1; } xfree(last_tokenid); last_tokenid = NULL; list_add(&watches, h, 0); } return 0; } COMMAND(cmd_reload) { const char *filename = NULL; int res = 0; if (params[0]) filename = params[0]; if ((res = config_read(filename))) printq("error_reading_config", strerror(errno)); if (res != -1) { printq("config_read_success", (res != -2 && filename) ? filename : prepare_path("config", 0)); config_changed = 0; } return res; } COMMAND(cmd_passwd) { struct gg_http *h; char *oldpasswd, *newpasswd; if (!last_tokenid) { printq("token_missing"); return -1; } if (!params[0] || !params[1]) { printq("not_enough_params", name); return -1; } if (!config_email) { printq("passwd_email"); return -1; } oldpasswd = xstrdup(config_password); if (oldpasswd && !config_password_cp1250) iso_to_cp((unsigned char *) oldpasswd); newpasswd = xstrdup(params[0]); iso_to_cp((unsigned char *) newpasswd); if (!(h = gg_change_passwd4(config_uin, config_email, (oldpasswd) ? oldpasswd : "", newpasswd, last_tokenid, params[1], 1))) { xfree(newpasswd); xfree(oldpasswd); printq("passwd_failed", strerror(errno)); return -1; } xfree(oldpasswd); xfree(last_tokenid); last_tokenid = NULL; list_add(&watches, h, 0); reg_password = newpasswd; return 0; } COMMAND(cmd_remind) { struct gg_http *h; if (!last_tokenid) { printq("token_missing"); return -1; } if (!params[0]) { printq("not_enough_params", name); return -1; } if (!(h = gg_remind_passwd3(config_uin, config_email, last_tokenid, params[0], 1))) { printq("remind_failed", strerror(errno)); return -1; } xfree(last_tokenid); last_tokenid = NULL; list_add(&watches, h, 0); return 0; } COMMAND(cmd_query) { char **p = xcalloc(3, sizeof(char*)); int i, res = 0; for (i = 0; params[i]; i++) p[i] = xstrdup(params[i]); p[i] = NULL; if (params[0] && (params[0][0] == '@' || strchr(params[0], ',')) && config_auto_conference) { struct conference *c = conference_create(params[0]); if (!c) { res = -1; goto cleanup; } ui_event("command", quiet, "query", c->name, NULL); xfree(p[0]); p[0] = xstrdup(c->name); } else { if (params[0] && params[0][0] == '#') { struct conference *c = conference_find(params[0]); if (!c) { printq("conferences_noexist", params[0]); res = -1; goto cleanup; } ui_event("command", quiet, "query", c->name, NULL); xfree(p[0]); p[0] = xstrdup(c->name); } else { char *param; if (params[0]) { char **tmp = array_make(params[0], " ,", 0, 0, 1); int i; for (i = 0; tmp[i]; i++) { int count = 0; list_t l; if (tmp[i][0] != '@') { if (!get_uin(tmp[i])) { printq("user_not_found", tmp[i]); res = -1; array_free(tmp); goto cleanup; } continue; } for (l = userlist; l; l = l->next) { struct userlist *u = l->data; list_t m; for (m = u->groups; m; m = m->next) { struct group *g = m->data; if (!strcasecmp(g->name, tmp[i] + 1)) count++; } } if (!count) { printq("group_empty", tmp[i] + 1); res = -1; array_free(tmp); goto cleanup; } } array_free(tmp); } param = xstrdup(params[0]); ui_event("command", quiet, "query", (params[0]) ? strip_chars(param, '\"') : NULL, NULL); xfree(param); } } if (params[0] && params[1]) { char *tmp = saprintf("/chat %s %s", p[0], p[1]); /* cmd_msg("chat", (const char **) p, NULL, quiet); */ command_exec(target, tmp, quiet); xfree(tmp); } cleanup: for (i = 0; p[i]; i++) xfree(p[i]); xfree(p); return res; } COMMAND(cmd_on) { if (match_arg(params[0], 'a', "add", 2)) { int flags, res; struct userlist *u = NULL; const char *t = params[2]; uin_t uin = 0; if (!params[1] || !params[2] || !params[3]) { printq("not_enough_params", name); return -1; } if (!(flags = event_flags(params[1]))) { printq("invalid_params", name); return -1; } if (!(uin = get_uin(params[2])) && strcmp(params[2], "*") && params[2][0] != '@') { printq("user_not_found", params[2]); return -1; } if (uin) { if ((u = userlist_find(uin, NULL)) && u->display) t = u->display; else t = itoa(uin); } if (!(res = event_add(flags, t, params[3], quiet))) config_changed = 1; return res; } if (match_arg(params[0], 'd', "del", 2)) { if (!params[1]) { printq("not_enough_params", name); return -1; } if (params[2]) { list_t l; for (l = events; l; l = l->next) { struct event *e = l->data; if (!strcasecmp(params[2], e->target) && event_flags(params[1]) == e->flags) { if (!event_remove(e->name, quiet)) { config_changed = 1; return 0; } else return -1; } } } if (!event_remove(params[1], quiet)) { config_changed = 1; return 0; } else return -1; } if (!params[0] || match_arg(params[0], 'l', "list", 2) || params[0][0] != '-') { list_t l; int count = 0; const char *ename = NULL; if (params[0] && params[0][0] != '-') ename = params[0]; else if (params[0] && match_arg(params[0], 'l', "list", 2)) ename = params[1]; for (l = events; l; l = l->next) { struct event *ev = l->data; if (ename && strcasecmp(ev->name, ename)) continue; printq((ev->flags & INACTIVE_EVENT) ? "events_list_inactive" : "events_list", event_format(abs(ev->flags)), event_format_target(ev->target), ev->action, ev->name); count++; } if (!count) printq("events_list_empty"); return 0; } printq("invalid_params", name); return -1; } COMMAND(cmd_echo) { printq("generic", (params && params[0]) ? params[0] : ""); return 0; } COMMAND(cmd_window) { ui_event("command", quiet, "window", (params) ? params[0] : NULL, (params && params[0]) ? params[1] : NULL, NULL); return 0; } COMMAND(cmd_bind) { ui_event("command", quiet, "bind", (params) ? params[0] : NULL, (params && params[0]) ? params[1] : NULL, (params && params[1]) ? params[2] : NULL, NULL); return 0; } COMMAND(cmd_test_vars) { char *tmp = variable_digest(); printq("generic", tmp); xfree(tmp); return 0; } COMMAND(cmd_test_ctcp) { if (!sess || !params[0]) return -1; gg_dcc_request(sess, get_uin(params[0])); return 0; } /* * command_exec() * * wykonuje polecenie zawarte w linii tekstu. * * - target - w którym oknie nastąpiło (NULL jeśli to nie query). * - xline - linia tekstu. * - quiet - czy mamy ukryć wynik. * * 0/-1. */ int command_exec(const char *target, const char *xline, int quiet) { char *cmd = NULL, *params_string = NULL, *last_name = NULL, *last_params = NULL, *line_save = NULL, *line = NULL; char short_cmd[2]; command_func_t *last_abbr = NULL; int abbrs = 0; int correct_command = 0; list_t l; if (!xline) return 0; if (!strcmp(xline, "")) { if (batch_mode && !batch_line) { quit_message_send = 1; ekg_exit(); } return 0; } #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(command_line, "(ss)", target, xline) { char *a, *b; PYTHON_HANDLE_RESULT("ss", &a, &b) { target = alloca(strlen(a) + 1); strlcpy((char *) target, a, strlen(a) + 1); xline = alloca(strlen(b) + 1); strlcpy((char *) xline, b, strlen(xline) + 1); } } PYTHON_HANDLE_FOOTER() if (python_handle_result == 0) { return 0; } #endif if (target && *xline != '/') { /* wykrywanie przypadkowo wpisanych poleceń */ if (config_query_commands) { for (l = commands; l; l = l->next) { struct command *c = l->data; int l = strlen(c->name); if (l > 2 && !strncasecmp(xline, c->name, l)) { if (!xline[l] || xisspace(xline[l])) { correct_command = 1; break; } } } } if (!correct_command) { const char *params[] = { target, xline, NULL }; if (strcmp(xline, "")) cmd_msg("chat", params, NULL, quiet); return 0; } } /* czy przepuścic coś jako wiadomość mimo, że zaczyna się od '/' ? */ if (config_slash_messages && target && xline[0] == '/' && strlen(xline) >= 2) { char *p = strchr(xline + 1, '/'); char *s = strchr(xline + 1, ' '); int pass = 0; /* "/ foo" -> "foo" */ if (xline[1] == ' ' && xline[2]) { xline += 2; pass = 1; /* "/bin/sh" -> "/bin/sh" */ } else if (p && (!s || p < s)) pass = 1; if (pass) { const char *params[] = { target, xline, NULL }; cmd_msg("chat", params, NULL, quiet); return 0; } } send_nicks_index = 0; line = line_save = xstrdup(xline); line = strip_spaces(line); if (*line == '/') line++; if (*line == '^') { quiet = 1; line++; } for (l = commands; l; l = l->next) { struct command *c = l->data; if (!isalpha_pl_PL(c->name[0]) && strlen(c->name) == 1 && line[0] == c->name[0]) { short_cmd[0] = c->name[0]; short_cmd[1] = 0; cmd = short_cmd; params_string = line + 1; } } if (!cmd) { char *tmp; tmp = line; cmd = line; while (*tmp && !xisspace(*tmp)) tmp++; if (*tmp) { *tmp = 0; params_string = tmp + 1; } else params_string = tmp; } for (l = commands; l; l = l->next) { struct command *c = l->data; if (!strcasecmp(c->name, cmd)) { last_abbr = c->function; last_name = c->name; last_params = (c->alias) ? "?" : c->params; abbrs = 1; break; } if (!strncasecmp(c->name, cmd, strlen(cmd))) { abbrs++; last_abbr = c->function; last_name = c->name; last_params = (c->alias) ? "?" : c->params; } else { if (last_abbr && abbrs == 1) break; } } if (last_abbr && abbrs == 1) { char **par; int res, len = strlen(last_params); /* * dla query potrzeba nam cudzysłowów, natomiast * dla całej reszty nie są one potrzebne (wymagałoby to * strippowania w wielu miejscach i zmienienia paru koncepcji) */ if (!strcasecmp(last_name, "query")) { par = array_make_quoted(params_string, " \t", len, 1, 1); } else par = array_make(params_string, " \t", len, 1, 1); command_processing = 1; res = (last_abbr)(last_name, (const char**) par, target, quiet); command_processing = 0; array_free(par); xfree(line_save); if (quit_command) ekg_exit(); return res; } if (strcmp(cmd, "")) printq("unknown_command", cmd); xfree(line_save); return -1; } /* * command_exec_format() * * formatuje string w formacie @a i wykonuje sformatowane polecenie. ekwiwalent: * char *tmp = saprintf(format, ...); * command_exec(target, tmp, quiet); * xfree(tmp); * * 0 - format byl NULL * -1 - polecenie nie zostalo znalezione (wynik command_exec()) * else - wynik dzialania handlera polecenia */ int command_exec_format(const char *target, int quiet, const char *format, ...) { char *command; va_list ap; int res; if (!format) return 0; va_start(ap, format); command = gg_vsaprintf(format, ap); va_end(ap); if (!command) return 0; res = command_exec(target, command, quiet); xfree(command); return res; } int binding_help(int a, int b) { print("help_quick"); return 0; } /* * binding_quick_list() * * wyświetla krótką i zwięzła listę dostępnych, zajętych i niewidocznych * ludzi z listy kontaktów. */ int binding_quick_list(int a, int b) { string_t list = string_init(NULL); list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; const char *format = NULL; char *tmp; if (!u->display) continue; switch (u->status) { case GG_STATUS_AVAIL: case GG_STATUS_AVAIL_DESCR: format = format_find("quick_list_avail"); break; case GG_STATUS_BUSY: case GG_STATUS_BUSY_DESCR: format = format_find("quick_list_busy"); break; case GG_STATUS_FFC: case GG_STATUS_FFC_DESCR: format = format_find("quick_list_ffc"); break; case GG_STATUS_DND: case GG_STATUS_DND_DESCR: format = format_find("quick_list_dnd"); break; case GG_STATUS_INVISIBLE: case GG_STATUS_INVISIBLE_DESCR: format = format_find("quick_list_invisible"); break; } if (!format) continue; if (!(tmp = format_string(format, u->display))) continue; string_append(list, tmp); xfree(tmp); } if (strlen(list->str) > 0) print("quick_list", list->str); string_free(list, 1); return 0; } int binding_toggle_contacts(int a, int b) { #ifdef WITH_UI_NCURSES static int last_contacts = -1; if (!config_contacts) { if ((config_contacts = last_contacts) == -1) config_contacts = 2; } else { last_contacts = config_contacts; config_contacts = 0; } ui_event("variable_changed", "contacts", NULL); config_changed = 1; #endif return 0; } COMMAND(cmd_alias_exec) { list_t l, tmp = NULL, m = NULL; int need_args = 0; for (l = aliases; l; l = l->next) { struct alias *a = l->data; if (!strcasecmp(name, a->name)) { tmp = a->commands; break; } } for (; tmp; tmp = tmp->next) { char *p; int __need = 0; for (p = tmp->data; *p; p++) { if (*p != '%') continue; p++; if (!*p) break; if (*p >= '1' && *p <= '9' && (*p - '0') > __need) __need = *p - '0'; if (need_args < __need) need_args = __need; } list_add(&m, tmp->data, strlen(tmp->data) + 1); } for (tmp = m; tmp; tmp = tmp->next) { string_t str; if (*((char *) tmp->data) == '/') str = string_init(NULL); else str = string_init("/"); if (need_args) { char *args[9], **arr, *s; int i; if (!params[0]) { printq("aliases_not_enough_params", name); string_free(str, 1); list_destroy(m, 1); return -1; } arr = array_make(params[0], "\t ", need_args, 1, 1); if (array_count(arr) < need_args) { printq("aliases_not_enough_params", name); string_free(str, 1); array_free(arr); list_destroy(m, 1); return -1; } for (i = 0; i < 9; i++) { if (i < need_args) args[i] = arr[i]; else args[i] = NULL; } s = format_string((char *) tmp->data, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); string_append(str, s); xfree(s); array_free(arr); } else { char *s = format_string((char *) tmp->data); string_append(str, s); xfree(s); if (params[0]) { string_append(str, " "); string_append(str, params[0]); } } command_exec(target, str->str, quiet); string_free(str, 1); } list_destroy(m, 1); return 0; } COMMAND(cmd_at) { list_t l; if (match_arg(params[0], 'a', "add", 2)) { const char *a_name = NULL; char *p, *a_command = NULL, *freq_str = NULL, *tmp; time_t period = 0, freq = 0, parsed; struct timer *t; if (!params[1] || !params[2]) { printq("not_enough_params", name); return -1; } if (!strncmp(params[2], "*/", 2) || xisdigit(params[2][0])) { a_name = params[1]; if (!strcmp(a_name, "(null)")) { printq("invalid_params", name); return -1; } for (l = timers; l; l = l->next) { t = l->data; if (t->at && !strcasecmp(t->name, a_name)) { printq("at_exist", a_name); return -1; } } p = xstrdup(params[2]); } else p = xstrdup(params[1]); if ((tmp = strchr(p, '/'))) { *tmp = 0; freq_str = ++tmp; } if ((parsed = parsetimestr(p)) == -1) { printq("invalid_params", name); xfree(p); return -1; } if (freq_str) { for (;;) { time_t _period = 0; if (xisdigit(*freq_str)) _period = atoi(freq_str); else { printq("invalid_params", name); xfree(p); return -1; } freq_str += strlen(itoa(_period)); if (strlen(freq_str)) { switch (xtolower(*freq_str++)) { case 'd': _period *= 86400; break; case 'h': _period *= 3600; break; case 'm': _period *= 60; break; case 's': break; default: printq("invalid_params", name); xfree(p); return -1; } } freq += _period; if (!*freq_str) break; } } xfree(p); /* plany na przeszłość? */ if ((period = parsed - time(NULL)) <= 0) { if (freq) { while (period <= 0) period += freq; } else { printq("at_back_to_past"); return -1; } } if (a_name) a_command = xstrdup(params[3]); else a_command = array_join((char **) params + 2, " "); if (a_command) { char *tmp = a_command; a_command = strip_spaces(a_command); if (!strcmp(a_command, "")) { printq("not_enough_params", name); xfree(tmp); return -1; } a_command = tmp; } else { printq("not_enough_params", name); return -1; } if ((t = timer_add(period, ((freq) ? 1 : 0), TIMER_COMMAND, 1, a_name, a_command))) { printq("at_added", t->name); if (freq) t->period = freq; if (!in_autoexec) config_changed = 1; } xfree(a_command); return 0; } if (match_arg(params[0], 'd', "del", 2)) { int del_all = 0; int ret = 1; if (!params[1]) { printq("not_enough_params", name); return -1; } if (!strcmp(params[1], "*")) { del_all = 1; ret = timer_remove_user(1); } else ret = timer_remove(params[1], 1, NULL); if (!ret) { if (del_all) printq("at_deleted_all"); else printq("at_deleted", params[1]); config_changed = 1; } else { if (del_all) printq("at_empty"); else { printq("at_noexist", params[1]); return -1; } } return 0; } if (!params[0] || match_arg(params[0], 'l', "list", 2) || params[0][0] != '-') { const char *a_name = NULL; int count = 0; if (params[0] && match_arg(params[0], 'l', "list", 2)) a_name = params[1]; else if (params[0]) a_name = params[0]; for (l = timers; l; l = l->next) { struct timer *t = l->data; struct timeval tv; struct tm *at_time; char tmp[100], tmp2[150]; const char *type_str; time_t sec, minutes = 0, hours = 0, days = 0; if (!t->at || (a_name && strcasecmp(t->name, a_name))) continue; count++; gettimeofday(&tv, NULL); at_time = localtime((time_t *) &t->ends.tv_sec); strftime(tmp, sizeof(tmp), format_find("at_timestamp"), at_time); if (t->persistent) { sec = t->period; if (sec > 86400) { days = sec / 86400; sec -= days * 86400; } if (sec > 3600) { hours = sec / 3600; sec -= hours * 3600; } if (sec > 60) { minutes = sec / 60; sec -= minutes * 60; } strlcpy(tmp2, "every ", sizeof(tmp2)); if (days) { strlcat(tmp2, itoa(days), sizeof(tmp2)); strlcat(tmp2, "d ", sizeof(tmp2)); } if (hours) { strlcat(tmp2, itoa(hours), sizeof(tmp2)); strlcat(tmp2, "h ", sizeof(tmp2)); } if (minutes) { strlcat(tmp2, itoa(minutes), sizeof(tmp2)); strlcat(tmp2, "m ", sizeof(tmp2)); } if (sec) { strlcat(tmp2, itoa(sec), sizeof(tmp2)); strlcat(tmp2, "s", sizeof(tmp2)); } } switch (t->type) { case TIMER_UI: type_str = "ui"; break; case TIMER_SCRIPT: type_str = "script"; break; case TIMER_COMMAND: type_str = "command"; break; default: type_str = "unknown"; } printq("at_list", t->name, tmp, t->command, type_str, ((t->persistent) ? tmp2 : "")); } if (!count) { if (a_name) { printq("at_noexist", a_name); return -1; } else printq("at_empty"); } return 0; } printq("invalid_params", name); return -1; } COMMAND(cmd_timer) { list_t l; if (match_arg(params[0], 'a', "add", 2)) { const char *t_name = NULL, *p; char *t_command = NULL; time_t period = 0; struct timer *t; int persistent = 0; if (!params[1] || !params[2]) { printq("not_enough_params", name); return -1; } if (xisdigit(params[2][0]) || !strncmp(params[2], "*/", 2)) { t_name = params[1]; if (!strcmp(t_name, "(null)")) { printq("invalid_params", name); return -1; } for (l = timers; l; l = l->next) { t = l->data; if (!t->at && !strcasecmp(t->name, t_name)) { printq("timer_exist", t_name); return -1; } } p = params[2]; t_command = xstrdup(params[3]); } else { p = params[1]; t_command = array_join((char **) params + 2, " "); } if ((persistent = !strncmp(p, "*/", 2))) p += 2; for (;;) { time_t _period = 0; if (xisdigit(*p)) _period = atoi(p); else { printq("invalid_params", name); xfree(t_command); return -1; } p += strlen(itoa(_period)); if (strlen(p)) { switch (xtolower(*p++)) { case 'd': _period *= 86400; break; case 'h': _period *= 3600; break; case 'm': _period *= 60; break; case 's': break; default: printq("invalid_params", name); xfree(t_command); return -1; } } period += _period; if (!*p) break; } if (t_command) { char *tmp = t_command; t_command = strip_spaces(t_command); if (!strcmp(t_command, "")) { printq("not_enough_params", name); xfree(tmp); return -1; } t_command = tmp; } else { printq("not_enough_params", name); return -1; } if ((t = timer_add(period, persistent, TIMER_COMMAND, 0, t_name, t_command))) { printq("timer_added", t->name); if (!in_autoexec) config_changed = 1; } xfree(t_command); return 0; } if (match_arg(params[0], 'd', "del", 2)) { int del_all = 0, ret; if (!params[1]) { printq("not_enough_params", name); return -1; } if (!strcmp(params[1], "*")) { del_all = 1; ret = timer_remove_user(0); } else ret = timer_remove(params[1], 0, NULL); if (!ret) { if (del_all) printq("timer_deleted_all"); else printq("timer_deleted", params[1]); config_changed = 1; } else { if (del_all) printq("timer_empty"); else { printq("timer_noexist", params[1]); return -1; } } return 0; } if (!params[0] || match_arg(params[0], 'l', "list", 2) || params[0][0] != '-') { const char *t_name = NULL; int count = 0; if (params[0] && match_arg(params[0], 'l', "list", 2)) t_name = params[1]; else if (params[0]) t_name = params[0]; for (l = timers; l; l = l->next) { struct timer *t = l->data; struct timeval tv; char *tmp; const char *type_str; long usec, sec, minutes = 0, hours = 0, days = 0; if (t->at || (t_name && strcasecmp(t->name, t_name))) continue; count++; gettimeofday(&tv, NULL); if (t->ends.tv_usec < tv.tv_usec) { sec = t->ends.tv_sec - tv.tv_sec - 1; usec = (t->ends.tv_usec - tv.tv_usec + 1000000) / 1000; } else { sec = t->ends.tv_sec - tv.tv_sec; usec = (t->ends.tv_usec - tv.tv_usec) / 1000; } if (sec > 86400) { days = sec / 86400; sec -= days * 86400; } if (sec > 3600) { hours = sec / 3600; sec -= hours * 3600; } if (sec > 60) { minutes = sec / 60; sec -= minutes * 60; } if (days) tmp = saprintf("%ldd %ldh %ldm %ld.%.3ld", days, hours, minutes, sec, usec); else if (hours) tmp = saprintf("%ldh %ldm %ld.%.3ld", hours, minutes, sec, usec); else if (minutes) tmp = saprintf("%ldm %ld.%.3ld", minutes, sec, usec); else tmp = saprintf("%ld.%.3ld", sec, usec); switch (t->type) { case TIMER_UI: type_str = "ui"; break; case TIMER_SCRIPT: type_str = "script"; break; case TIMER_COMMAND: type_str = "command"; break; default: type_str = "unknown"; } printq("timer_list", t->name, tmp, t->command, type_str, (t->persistent) ? "*" : ""); xfree(tmp); } if (!count) { if (t_name) { printq("timer_noexist", t_name); return -1; } else printq("timer_empty"); } return 0; } printq("invalid_params", name); return -1; } #ifdef WITH_PYTHON COMMAND(cmd_python) { if (!params[0] || !strncasecmp(params[0], "li", 2)) return python_list(quiet); if (!strncasecmp(params[0], "lo", 2)) return python_load(params[1], quiet); if (!strncasecmp(params[0], "u", 1)) return python_unload(params[1], quiet); if (!strncasecmp(params[0], "ru", 2)) return python_run(params[1], quiet); if (!strncasecmp(params[0], "e", 1)) return python_exec(params[1]); if (!strncasecmp(params[0], "re", 2)) { python_finalize(); python_initialize(); python_autorun(); return 0; } printq("invalid_params", name); return -1; } #endif COMMAND(cmd_conference) { if (!params[0] || match_arg(params[0], 'l', "list", 2) || params[0][0] == '#') { list_t l, r; int count = 0; const char *cname = NULL; if (params[0] && match_arg(params[0], 'l', "list", 2)) cname = params[1]; else if (params[0]) cname = params[0]; for (l = conferences; l; l = l->next) { struct conference *c = l->data; string_t recipients; const char *recipient; int first = 0; recipients = string_init(NULL); if (cname && strcasecmp(cname, c->name)) continue; for (r = c->recipients; r; r = r->next) { uin_t uin = *((uin_t *) (r->data)); struct userlist *u = userlist_find(uin, NULL); if (u && u->display) recipient = u->display; else recipient = itoa(uin); if (first++) string_append_c(recipients, ','); string_append(recipients, recipient); count++; } print(c->ignore ? "conferences_list_ignored" : "conferences_list", c->name, recipients->str); string_free(recipients, 1); } if (!count) { if (params[0] && params[0][0] == '#') { printq("conferences_noexist", params[0]); return -1; } else printq("conferences_list_empty"); } return 0; } if (match_arg(params[0], 'j', "join", 2)) { struct conference *c; uin_t uin; if (!params[1] || !params[2]) { printq("not_enough_params", name); return -1; } if (params[1][0] != '#') { printq("conferences_name_error"); return -1; } if (!(c = conference_find(params[1]))) { printq("conferences_noexist", params[1]); return -1; } if (!(uin = get_uin(params[2]))) { printq("unknown_user", params[2]); return -1; } if (conference_participant(c, uin)) { printq("conferences_already_joined", format_user(uin), params[1]); return -1; } list_add(&c->recipients, &uin, sizeof(uin)); printq("conferences_joined", format_user(uin), params[1]); return 0; } if (match_arg(params[0], 'a', "add", 2)) { if (!params[1]) { printq("not_enough_params", name); return -1; } if (params[2]) { if (params[1][0] != '#') { printq("conferences_name_error"); return -1; } else conference_add(params[1], params[2], quiet); } else conference_create(params[1]); return 0; } if (match_arg(params[0], 'd', "del", 2)) { if (!params[1]) { printq("not_enough_params", name); return -1; } if (!strcmp(params[1], "*")) conference_remove(NULL, quiet); else { if (params[1][0] != '#') { printq("conferences_name_error"); return -1; } conference_remove(params[1], quiet); } return 0; } if (match_arg(params[0], 'r', "rename", 2)) { if (!params[1] || !params[2]) { printq("not_enough_params", name); return -1; } if (params[1][0] != '#' || params[2][0] != '#') { printq("conferences_name_error"); return -1; } conference_rename(params[1], params[2], quiet); return 0; } if (match_arg(params[0], 'i', "ignore", 2)) { if (!params[1]) { printq("not_enough_params", name); return -1; } if (params[1][0] != '#') { printq("conferences_name_error"); return -1; } conference_set_ignore(params[1], 1, quiet); return 0; } if (match_arg(params[0], 'u', "unignore", 2)) { if (!params[1]) { printq("not_enough_params", name); return -1; } if (params[1][0] != '#') { printq("conferences_name_error"); return -1; } conference_set_ignore(params[1], 0, quiet); return 0; } if (match_arg(params[0], 'f', "find", 2)) { struct conference *c; char *tmp = NULL; list_t l; if (!params[1]) { printq("not_enough_params", name); return -1; } if (params[1][0] != '#') { printq("conferences_name_error"); return -1; } c = conference_find(params[1]); if (c) { for (l = c->recipients; l; l = l->next) { tmp = saprintf("/find --uin %d", *((uin_t *) (l->data))); command_exec(target, tmp, quiet); xfree(tmp); } } else { printq("conferences_noexist", params[1]); return -1; } return 0; } printq("invalid_params", name); return -1; } COMMAND(cmd_last) { list_t l; uin_t uin = 0; int last_n = 0, count = 0, i = 0, clear = 0; time_t n, period_start = 0, period_end = 0; struct tm *now; if (params[0]) { char **arr = NULL; array_add(&arr, xstrdup(params[0])); if (params[1]) { char **tmp = array_make(params[1], " \t", 0, 1, 1); for (i = 0; tmp[i]; i++) array_add(&arr, xstrdup(tmp[i])); array_free(tmp); } /* zobaczmy, co tu mamy ... */ for (i = 0; arr[i]; i++) { if (match_arg(arr[i], 'c', "clear", 2)) { clear = 1; continue; } if (match_arg(arr[i], 'u', "user", 2) && arr[i + 1]) { if (!(uin = get_uin(arr[++i]))) { printq("user_not_found", arr[i]); array_free(arr); return -1; } continue; } if (match_arg(arr[i], 'n', "number", 2) && arr[i + 1]) { last_n = strtol(arr[++i], NULL, 0); continue; } if (match_arg(arr[i], 'p', "period", 2) && arr[i + 1]) { char *foo, *tmp = xstrdup(arr[++i]); if ((foo = strchr(tmp, '-'))) { *foo = 0; if (foo != tmp) period_start = parsetimestr(tmp); foo++; if (*foo) period_end = parsetimestr(foo); } else period_start = parsetimestr(tmp); xfree(tmp); if (!(period_start == -1 || period_end == -1)) continue; } if (!i && (uin = get_uin(arr[i]))) continue; else { if (i) printq("invalid_params", name); else printq("user_not_found", arr[i]); array_free(arr); return -1; } } array_free(arr); } /* musimy policzyć ręcznie */ for (l = lasts; l; l = l->next) { struct last *ll = l->data; if (uin == 0 || uin == ll->uin) { if (period_end && ll->time > period_end) break; if (!period_start || ll->time > period_start) count++; } } if (!count) { if (uin) { printq("last_list_empty_nick", format_user(uin)); return -1; } printq("last_list_empty"); return 0; } n = time(NULL); now = localtime(&n); for (l = lasts, i = 0; l; ) { struct last *ll = l->data; struct tm *tm, *st; char buf[100], buf2[100], *time_str = NULL; l = l->next; if (uin == 0 || uin == ll->uin) { /* jesli ma być początek, to go szukamy */ if (period_start && ll->time < period_start) continue; /* za daleko? wychodzimy! */ if (period_end && ll->time > period_end) break; /* jesteśmy w dobrym okresie, ile ostatnich wyświetlić? */ if (last_n && i++ < (count - last_n)) continue; if (clear) { xfree(ll->message); list_remove(&lasts, ll, 1); } else { tm = localtime(&ll->time); strftime(buf, sizeof(buf), format_find("last_list_timestamp"), tm); if (ll->type == 0 && !(ll->sent_time - config_time_deviation <= ll->time && ll->time <= ll->sent_time + config_time_deviation)) { st = localtime(&ll->sent_time); strftime(buf2, sizeof(buf2), format_find((tm->tm_yday == now->tm_yday) ? "last_list_timestamp_today" : "last_list_timestamp"), st); time_str = saprintf("%s/%s", buf, buf2); } else time_str = xstrdup(buf); if (ll->type == 1) { if (config_last & 4) printq("last_list_out", time_str, format_user(ll->uin), ll->message); } else printq("last_list_in", time_str, format_user(ll->uin), ll->message); xfree(time_str); } } } if (clear) { if (count == 1) printq("last_clear_one"); else printq("last_clear"); } return 0; } COMMAND(cmd_queue) { list_t l; uin_t uin = 0; int clear = 0, count = 0, i; if (strcasecmp(name, "_queue") && sess && sess->state == GG_STATE_CONNECTED) { printq("queue_wrong_use"); return -1; } if (params[0]) { char **arr = NULL; array_add(&arr, xstrdup(params[0])); if (params[1]) { char **tmp = array_make(params[1], " \t", 0, 1, 1); for (i = 0; tmp[i]; i++) array_add(&arr, xstrdup(tmp[i])); array_free(tmp); } for (i = 0; arr[i]; i++) { if (match_arg(arr[i], 'c', "clear", 2)) { clear = 1; continue; } if (match_arg(arr[i], 'u', "user", 2) && arr[i + 1]) { if (!(uin = get_uin(arr[++i]))) { printq("user_not_found", arr[i]); array_free(arr); return -1; } continue; } printq("invalid_params", name); array_free(arr); return -1; } array_free(arr); } if (uin) count = msg_queue_count_uin(uin); else count = msg_queue_count(); if (!count) { if (uin) { printq("queue_empty_uin", format_user(uin)); return -1; } else printq("queue_empty"); return 0; } if (clear) { if (uin) { msg_queue_remove_uin(uin); printq("queue_clear_uin", format_user(uin)); } else { msg_queue_free(); printq("queue_clear"); } } else for (l = msg_queue; l; l = l->next) { struct msg_queue *m = l->data; struct tm *tm; char *fu = NULL; char buf[100]; tm = localtime(&m->time); strftime(buf, sizeof(buf), format_find("queue_list_timestamp"), tm); if (m->uin_count > 1) { string_t s = string_init(format_user(*(m->uins))); int i; for (i = 1; i < m->uin_count; i++) { string_append(s, ","); string_append(s, format_user(m->uins[i])); } fu = string_free(s, 0); } else fu = xstrdup(format_user(*(m->uins))); printq("queue_list_message", buf, fu, m->msg); xfree(fu); } return 0; } /* eksperymentalne wykrywanie niewidoczności, a w zasadzie sprawdzanie czy klient * jest połączony */ int check_conn(uin_t uin) { struct userlist *u; if (!sess || sess->state != GG_STATE_CONNECTED) return -1; if ((u = userlist_find(uin, NULL))) { list_t l; struct spied s; for (l = spiedlist; l; l = l->next) { struct spied *s = l->data; if (uin == s->uin) { if (s->timeout == -1) return 0; else return -1; } } s.uin = uin; s.timeout = SPYING_RESPONSE_TIMEOUT; gettimeofday(&(s.request_sent), NULL); list_add(&spiedlist, &s, sizeof(s)); gg_debug(GG_DEBUG_MISC, "// ekg: spying %d\n", uin); } return gg_image_request(sess, uin, 0, time(NULL)); } static int check_conn_all_wrapper(const char *group, int quiet) { list_t l; int any = 0; int ret = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (group_member(u, group + 1)) { const char *params[] = { itoa(u->uin), NULL }; any = 1; if (cmd_check_conn("check_conn", params, NULL, quiet)) ret = 1; } } if (!any) printq("group_empty", group); return ret; } COMMAND(cmd_check_conn) { uin_t uin; const char *par; list_t l; if (!params[0] && !target) { printq("not_enough_params", name); return -1; } if (params[0] && params[0][0] == '@') { return check_conn_all_wrapper(params[0], quiet); } if (params[0]) { if (match_arg(params[0], 'u', "update", 2)) { for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (GG_S_I(u->status)) check_conn(u->uin); } return 0; } if (match_arg(params[0], 's', "scan", 2)) { for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (GG_S_NA(u->status) && group_member(u, "spied")) check_conn(u->uin); } return 0; } } if (!sess || sess->state != GG_STATE_CONNECTED) { printq("not_connected"); return -1; } par = params[0] ? params[0] : target; if (!(uin = get_uin(par))) { printq("user_not_found", par); return -1; } /* zresetujmy maszynę szpiegującą, dla testów */ for (l = spiedlist; l; l = l->next) { struct spied *s = l->data; if (s->uin == uin) { list_remove(&spiedlist, s, 1); break; } } return check_conn(uin); } /* * command_add_compare() * * funkcja porównująca nazwy komend, by występowały alfabetycznie w liście. * * - data1, data2 - dwa wpisy komend do porównania. * * zwraca wynik strcasecmp() na nazwach komend. */ static int command_add_compare(void *data1, void *data2) { struct command *a = data1, *b = data2; if (!a || !a->name || !b || !b->name) return 0; return strcasecmp(a->name, b->name); } /* * command_add() * * dodaje komendę. * * - name - nazwa komendy, * - params - definicja parametrów (szczegóły poniżej), * - function - funkcja obsługująca komendę, * - alias - czy komenda jest aliasem, * - params_help - opis parametrów, * - brief_help - krótki opis komendy, * - long_help - szczegółowy opis komendy. * * 0 jeśli się udało, -1 jeśli błąd. */ int command_add(const char *name, const char *params, command_func_t function, int alias, const char *params_help, const char *brief_help, const char *long_help) { struct command c; c.name = xstrdup(name); c.params = xstrdup(params); c.function = function; c.alias = alias; c.params_help = xstrdup(params_help); c.brief_help = xstrdup(brief_help); c.long_help = xstrdup(long_help); return (list_add_sorted(&commands, &c, sizeof(c), command_add_compare) != NULL) ? 0 : -1; } /* * command_remove() * * usuwa komendę z listy. * * - name - nazwa komendy. */ int command_remove(const char *name) { list_t l; for (l = commands; l; l = l->next) { struct command *c = l->data; if (!strcasecmp(name, c->name)) { xfree(c->name); xfree(c->params); xfree(c->params_help); xfree(c->brief_help); xfree(c->long_help); list_remove(&commands, c, 1); return 0; } } return -1; } /* * rodzaje parametrów komend: * * '?' - olewamy, * 'U' - ręcznie wpisany uin, nadawca mesgów, * 'u' - nazwa lub uin z kontaktów, nazwa konferencji, ręcznie wpisany uin, nadawca mesgów, * 'c' - komenda, * 'i' - nicki z listy ignorowanych osób, * 'b' - nicki z listy blokowanych osób, * 'v' - nazwa zmiennej, * 'd' - komenda dcc, * 'p' - komenda python, * 'w' - komenda window, * 'f' - plik, * 'e' - nazwy zdarzeń, * 'I' - poziomy ignorowania. */ /* * command_init() * * inicjuje listę domyślnych komend. */ void command_init() { command_add ( "add", "U??", cmd_add, 0, " [numer] [alias] [opcje]", "dodaje użytkownika do listy kontaktów", "\n" " -f, --find [alias] dodaje ostatnio wyszukaną osobę\n" "\n" "W przypadku opcji %T--find%n alias jest wymagany, jeśli w ostatnim " "wyszukiwaniu nie znaleziono pseudonimu. " "Pozostałe opcje identyczne jak dla polecenia %Tlist%n (dotyczące " "wpisu). W oknie rozmowy z kimś spoza naszej listy kontaktów jako " "parametr można podać sam alias."); command_add ( "alias", "??", cmd_alias, 0, " [opcje]", "zarządzanie aliasami", "\n" " -a, --add dodaje alias\n" " -A, --append dodaje komendę do aliasu\n" " -d, --del |* usuwa alias\n" " [-l, --list] [alias] wyświetla listę aliasów\n" "\n" "W komendzie można użyć formatów od %T%%1%n do %T%%9%n i w " "ten sposób ustalić kolejność przekazywanych argumentów. Aby otrzymać " "znak procenta w aliasie, należy zastosować zapis %T%%%%%n."); command_add ( "away", "r", cmd_away, 0, " [powód/-]", "zmienia stan na zajęty", "\n" "Jeśli włączona jest odpowiednia opcja %Trandom_reason%n i nie " "podano powodu, zostanie wylosowany z pliku %Taway.reasons%n. " "Podanie ,,%T-%n'' zamiast powodu spowoduje wyczyszczenie bez " "względu na ustawienia zmiennych."); command_add ( "at", "???c", cmd_at, 0, " [opcje]", "planuje wykonanie komend", "\n" " -a, --add [nazwa] [/częst.] tworzy nowy plan\n" " -d, --del |* usuwa plan\n" " [-l, --list] [nazwa] wyświetla listę planów\n" "\n" "Czas podaje się w formacie " "[[[yyyy]mm]dd]HH[:]MM[.SS], gdzie %Tyyyy%n to rok, %Tmm%n to miesiąc, " "%Tdd%n to dzień, %THH:MM%n to godzina, a %T.SS%n to sekundy. " "Minimalny format to %THH:MM%n (dwukropek można pominąć). " "Po kropce można podać sekundy, a przed godziną odpowiednio: dzień " "miesiąca, miesiąc, rok. Jeśli podanie zostana częstotliwość, wyrażona " "w sekundach lub za pomocą przyrostków takich, jak dla komendy %Ttimer%n, " "to komenda będzie wykonywana w zadanych odstepach czasu od momentu jej " "pierwszego wykonania."); command_add ( "back", "r", cmd_away, 0, " [powód/-]", "zmienia stan na dostępny", "\n" "Jeśli włączona jest odpowiednia opcja %Trandom_reason%n i nie " "podano powodu, zostanie wylosowany z pliku %Tback.reasons%n. " "Podanie ,,%T-%n'' zamiast powodu spowoduje wyczyszczenie bez " "względu na ustawienia zmiennych."); command_add ( "beep", "", cmd_beep, 0, "", "wydaje dźwięk", ""); #ifdef WITH_IOCTLD command_add ( "beeps_spk", "?", cmd_beeps_spk, 0, " ", "wydaje dźwięki zgodnie z sekwencją", "\n" "Kolejne dźwięki oddzielone są przecinkami. Dźwięk składa się " "z tonu w hercach i długości trwania w mikrosekundach oddzielonej " "ukośnikiem (,,%T/%n''). Jeśli nie podano czasu trwania, domyślna " "wartość to 0,1s.\n" "\n" "Zamiast sekwencji można podać nazwę formatu z themu."); command_add ( "blink_leds", "?", cmd_blink_leds, 0, " ", "odtwarza sekwencję na diodach LED", "\n" "Kombinacje diod oddzielone są przecinkami. Jeśli po kombinacji " "występuje znak ukośnika (,,%T/%n''), po nim podany jest czas trwania " "w mikrosekundach. Domyślny czas trwania to 0,1s. Kombinacja jest " "mapą bitową o następujących " "wartościach: 1 - NumLock, 2 - ScrollLock, 4 - CapsLock. Na " "przykład włączenie NumLock i CapsLock jednocześnie to 1+4 czyli " "5.\n" "\n" "Zamiast sekwencji można podać nazwę formatu z themu."); #endif command_add ( "block", "u?", cmd_block, 0, " [numer/alias]", "dodaje do listy blokowanych", ""); command_add ( "bind", "???", cmd_bind, 0, " [opcje]", "przypisywanie akcji klawiszom", "\n" " -a, --add przypisuje nową sekwencję\n" " -d, --del usuwa podaną sekwencję\n" " [-l, --list] [sekwencja] wyświetla przypisane sekwencje\n" " -L, --list-default [sekwencja] j.w. plus domyślne sekwencje\n" "\n" "Dostępne sekwencje to: Ctrl-, Alt-, F, Enter, " "Backspace, Delete, Insert, Home, End, Left, Right, Up, Down, " "PageUp, PageDown.\n" "\n" "Dostępne akcje to: backward-word, forward-word, kill-word, toggle-input, cancel-input, backward-delete-char, beginning-of-line, end-of-line, delete-char, backward-page, forward-page, kill-line, yank, accept-line, line-discard, quoted-insert, word-rubout, backward-char, forward-char, previous-history, next-history, complete, quick-list, toggle-contacts, next-contacts-group, ignore-query, contacts-scroll-up, contacts-scroll-down. " "Każda inna akcja będzie traktowana jako komenda do wykonania."); command_add ( "change", "?", cmd_change, 0, " ", "zmienia informacje w katalogu publicznym", "\n" " -f, --first \n" " -l, --last \n" " -n, --nick \n" " -b, --born \n" " -c, --city \n" " -N, --familyname nazwisko panieńskie\n" " -C, --familycity miasto rodzinne\n" " -F, --female kobieta\n" " -M, --male mężczyzna\n" "\n" "Jeśli któryś z parametrów nie zostanie podany, jego wartość " "zostanie wyczyszczona w katalogu publicznym. Podanie parametru " ",,%T-%n'' wyczyści %Twszystkie%n pola."); command_add ( "chat", "u?", cmd_msg, 0, " ", "wysyła wiadomość w rozmowie", "\n" "Można podać większą ilość odbiorców oddzielając ich numery lub " "pseudonimy przecinkiem (ale bez odstępów). W takim wypadku " "zostanie rozpoczęta nowa konferencja. Jeśli zamiast odbiorcy " "podany zostanie znak ,,%T*%n'', to wiadomość będzie wysłana do " "wszystkich aktualnych rozmówców."); command_add ( "check_conn", "u?", cmd_check_conn, 0, " [opcje] [numer/alias/@grupa]", "sprawdza, czy podany użytkownik jest połączony z serwerem", "\n" " -u, --update sprawdza, czy osoby oznaczone jako niewidoczne są nadal połączone\n" " -s, --scan sprawdza, czy osoby należące do grupy %Tspied%n i mające stan\n" " %Tniedostępny%n są połączone z serwerem\n" "\n" "EKSPERYMENTALNE! Sprawdza, czy podana osoba jest połączona. Klient tej osoby " "musi obsługiwać obrazki. Działa w przypadku GG 6.x dla Windows. Jeśli ktoś " "używa innego klienta, to może mu się pojawić pusta wiadomość (np. TLEN). " "Dzięki tej funkcji " "można sprawdzić czy osoba, którą widzimy jako niedostępna, jest " "niewidoczna. Jeżeli brak aliasu jako parametr, sprawdzana jest osoba, " "z którą rozmowa znajduję się w aktualnym okienku.\n" "\n" "Jeśli osoba należy do grupy %Tspied%n, to w miarę możliwości jej stan jest " "śledzony na bieżąco, jednak ze względu na różne zachowanie oryginalnego klienta, należy co " "pewien czas dokonywać ręcznego sprawdzania czy nasza wiedza o stanie niewidocznym danej osoby " "jest wciąż aktualna. Należy więc dodać timer, który np. co 60 sekund wywoła polecenie " "%Tcheck_conn -u%n oraz polecenie %Tcheck_conn -s%n.\n" "\n" "Opcja " "%T-s%n zakłada, że serwer prawidłowo zakolejkuje wiadomość dla użytkownika niedostępnego i nie wysyła " "więcej niż jednej wiadomości testującej w czasie sesji połączenia z serwerem - czasami, ze względu na " "różne warunki (awarie serwerów, itp.) taka wiadomość przepada i danej osoby nie wykryjemy jako niewidocznej; " "należy wtedy połączyć się ponownie z serwerem lub sprawdzić daną osobę ręcznie za pomocą %Tcheck_conn%n. Takie " "zachowanie ma na celu uniknięcie zapełnienia skrzynek na zakolejkowane wiadomości śledzonym użytkownikom. " "Pamiętaj, podglądanie innych osób jest nieetyczne..."); command_add ( "cleartab", "?", cmd_cleartab, 0, " [opcje]", "czyści listę nicków do dopełnienia", "\n" " -o, --offline usuwa tylko nieobecnych"); command_add ( "connect", "??", cmd_connect, 0, " [[numer] hasło]", "łączy się z serwerem", "\n" "Jeśli podano jeden parametr, jest on traktowany jako hasło, " "a jeśli podano dwa, są to kolejno numer i hasło. Dane te są " "ustawiane w konfiguracji i zostaną utrwalone po wydaniu komendy " "%Tsave%n."); command_add ( "dcc", "duf?", cmd_dcc, 0, " [opcje]", "obsługa bezpośrednich połączeń", "\n" " [r]send <ścieżka> wysyła podany plik\n" " get [numer/alias/#id] akceptuje przysyłany plik\n" " resume [numer/alias/#id] wznawia pobieranie pliku\n" " [r]voice rozpoczyna rozmowę głosową\n" " close zamyka połączenie\n" " list wyświetla listę połączeń\n" "\n" "Połączenia bezpośrednie wymagają włączonej opcji %Tdcc%n. " "Komendy %Trsend%n i %Trvoice%n wysyłają żądanie połączenia się " "drugiego klienta z naszym i są przydatne, gdy nie jesteśmy w stanie " "się z nim sami połączyć."); command_add ( "del", "u?", cmd_del, 0, " |*", "usuwa użytkownika z listy kontaktów", ""); command_add ( "disconnect", "r", cmd_connect, 0, " [powód/-]", "rozłącza się z serwerem", "\n" "Parametry identyczne jak dla komendy %Tquit%n.\n" "\n" "Jeśli włączona jest opcja %Tauto_reconnect%n, to po wywołaniu " "tej komendy program nadal będzie próbował się automatycznie " "łączyć po określonym czasie."); command_add ( "dnd", "r", cmd_away, 0, " [powód/-]", "zmienia stan na nie przeszkadzać", "\n" "Jeśli włączona jest odpowiednia opcja %Trandom_reason%n i nie " "podano powodu, zostanie wylosowany z pliku %Tdnd.reasons%n. " "Podanie ,,%T-%n'' zamiast powodu spowoduje wyczyszczenie bez " "względu na ustawienia zmiennych."); command_add ( "echo", "?", cmd_echo, 0, " [tekst]", "wyświetla podany tekst", ""); command_add ( "exec", "?", cmd_exec, 0, " [opcje] ", "uruchamia polecenie systemowe", "\n" " -m, --msg [numer/alias] wysyła wynik do danej osoby\n" " -b, --bmsg [numer/alias] wysyła wynik w jednej wiadomości\n" "\n" "Poprzedzenie polecenia znakiem ,,%T^%n'' ukryje informację o " "zakończeniu. Zapisanie opcji wielkimi literami (np. %T-B%n) " "spowoduje umieszczenie polecenia w pierwszej linii wysyłanego " "wyniku. Ze względu na budowę klienta, numery i aliasy " "%Tnie będą%n dopełniane Tabem."); command_add ( "!", "?", cmd_exec, 0, " [opcje] ", "synonim dla %Texec%n", ""); command_add ( "ffc", "r", cmd_away, 0, " [powód/-]", "zmienia stan na poGGadaj ze mną", "\n" "Jeśli włączona jest odpowiednia opcja %Trandom_reason%n i nie " "podano powodu, zostanie wylosowany z pliku %Tffc.reasons%n. " "Podanie ,,%T-%n'' zamiast powodu spowoduje wyczyszczenie bez " "względu na ustawienia zmiennych."); command_add ( "find", "u", cmd_find, 0, " [numer|opcje]", "przeszukiwanie katalogu publicznego", "\n" " -u, --uin \n" " -f, --first \n" " -l, --last \n" " -n, --nick \n" " -c, --city \n" " -b, --born zakres roku urodzenia\n" " -a, --active tylko dostępni\n" " -F, --female kobiety\n" " -M, --male mężczyźni\n" " -s, --start wyświetla od n-tego numeru\n" " -A, --all wyświetla wszystkich\n" " -S, --stop zatrzymuje wszystkie poszukiwania"); command_add ( "for", "?", cmd_for, 0, " [opcje] ", "wykonanie polecenia w pętli", "\n" "Polecenie zostanie wykonane w pętli od wartości %Tod%n do " "wartości %Tdo%n włącznie. Opcje:\n" "\n" " -s, --step \n" " -w, --width\n" "\n" "Jeżeli przyrost nie zostanie podany lub zostanie podane 0, " "to zostanie użyty przyrost 1 (dla %Tdo%n większego od %Tod%n) " "lub -1 (w przeciwnym przypadku). Jeżeli %Tdo%n będzie równe " "%Tod%n, to polecenie zostanie wykonane tylko raz. W poleceniu " "wszystkie wystąpienia %T%%n%n zostaną zamienione na aktualną " "wartość zmiennej iteracyjnej (czyli kolejno na wszystkie liczby " "z podanego zakresu). Znak procentu można uzyskać pisząc %T%%%%%n. " "Jeżeli zostanie podana opcja %T-w%n, to wszystkie liczby będą " "dopełnione zerami do szerokości największej z nich."); command_add ( "help", "cv", cmd_help, 0, " [polecenie] [zmienna]", "wyświetla informację o poleceniach", "\n" "Możliwe jest wyświetlenie informacji o zmiennych, jeśli jako " "polecenie poda się %Tset%n"); command_add ( "?", "cv", cmd_help, 0, " [polecenie] [zmienna]", "synonim dla %Thelp%n", ""); command_add ( "ignore", "uI", cmd_ignore, 0, " [numer/alias/@grupa] [poziom]", "dodaje do listy ignorowanych", "\n" "Dostępne poziomy ignorowania:\n" " - status - całkowicie ignoruje stan\n" " - descr - ignoruje tylko opisy\n" " - notify - nie wyświetla zmian stanu\n" " - msg - ignoruje wiadomości\n" " - smsaway - nie przesyła wiadomości podczas nieobecności\n" " - display - nie wypisuje osoby na liście kontaktów (w ncurses)\n" " - dcc - ignoruje połączenia DCC\n" " - events - ignoruje zdarzenia związane z użytkownikiem\n" " - * - wszystkie poziomy\n" "\n" "Poziomy można łączyć ze sobą za pomocą przecinka lub ,,%T|%n''. " "Próba dodania osoby już istniejącej spowoduje zmodyfikowanie (dodanie) " "poziomów ignorowania."); command_add ( "invisible", "r", cmd_away, 0, " [powód/-]", "zmienia stan na niewidoczny", "\n" "Jeśli włączona jest odpowiednia opcja %Trandom_reason%n i nie " "podano powodu, zostanie wylosowany z pliku %Tquit.reasons%n. " "Podanie ,,%T-%n'' zamiast powodu spowoduje wyczyszczenie bez " "względu na ustawienia zmiennych."); #ifdef HAVE_OPENSSL command_add ( "key", "uu", cmd_key, 0, " [opcje]", "zarządzanie kluczami dla SIM", "\n" " -g, --generate generuje parę kluczy użytkownika\n" " -s, --send wysyła nasz klucz publiczny\n" " -d, --delete usuwa klucz publiczny\n" " [-l, --list] [numer/alias] wyświetla posiadane klucze publiczne"); #endif command_add ( "last", "uu", cmd_last, 0, " [opcje]", "wyświetla lub czyści ostatnie wiadomości", "\n" " -c, --clear czyści podane wiadomości lub wszystkie\n" " -n, --number ostatnie %Tn%n wiadomości\n" " -p, --period wiadomości z podanego okresu\n" " -u, --user wiadomości od danego użytkownika\n" "\n" "Format zapisu czasu w przypadku opcji ,,%T--period%n'' jest taki sam, jak " "dla polecenia %Tat%n. Można podać zarówno początek, jak i koniec lub tylko " "jedną z granic."); command_add ( "list", "u?", cmd_list, 0, " [alias|@grupa|opcje]", "zarządzanie listą kontaktów", "\n" "Wyświetlanie osób o podanym stanie \"list [-a|-b|-i|-I|-B|-d|-m|-o]\":\n" " -a, --active dostępne\n" " -b, --busy zajęte\n" " -f, --ffc chcące poGGadać\n" " -D, --dnd nie chcące, żeby im przeszkadzano\n" " -i, --inactive niedostępne\n" " -I, --invisible niewidoczne\n" " -B, --blocked blokujące nas\n" " -d, --description osoby z opisem\n" " -m, --member <@grupa> osoby należące do danej grupy\n" " -o, --offline osoby dla których jesteśmy\n" " niedostępni\n" "\n" "Przeszukanie listy przy pomocy wyrażenia regularnego: \"list -r\", " "\"list --regex\" (zobacz też: /help /set regex_flags).\n" "\n" "Wyświetlanie członków grupy: \"list @grupa\". Wyświetlanie osób " "spoza grupy: \"list !@grupa\".\n" "\n" "Zmiana wpisów listy kontaktów \"list \":\n" " -f, --first \n" " -l, --last \n" " -n, --nick pseudonim (nie jest używany)\n" " -d, --display wyświetlana nazwa\n" " -u, --uin \n" " -g, --group [+/-]<@grupa> dodaje lub usuwa z grupy\n" " można podać więcej grup po\n" " przecinku\n" " -p, --phone numer telefonu komórkowego\n" " -e, --email adres e-mail\n" " -o, --offline bądź niedostępny dla danej osoby\n" " -O, --online bądź widoczny dla danej osoby\n" "\n" "Dwie ostatnie opcje działają tylko, gdy włączony jest tryb ,,tylko " "dla znajomych''.\n" "\n" "Lista kontaktów na serwerze \"list [-p|-g|-c|-P|-G|-C]\":\n" " -p, --put umieszcza na serwerze\n" " -P, --put-config umieszcza na serwerze razem\n" " z konfiguracją\n" " -g, --get pobiera z serwera\n" " -G, --get-config pobiera z serwera razem z konfiguracją\n" " -c, --clear usuwa listę z serwera\n" " -C, --clear-config usuwa listę wraz z konfiguracją\n" " z serwera"); command_add ( "msg", "u?", cmd_msg, 0, " ", "wysyła wiadomość", "\n" "Można podać większą ilość odbiorców oddzielając ich numery lub " "pseudonimy przecinkiem (ale bez odstępów). Jeśli zamiast odbiorcy " "podany zostanie znak ,,%T*%n'', to wiadomość będzie wysłana do " "wszystkich aktualnych rozmówców."); command_add ( "on", "?euc", cmd_on, 0, " [opcje]", "zarządzanie zdarzeniami", "\n" " -a, --add dodaje zdarzenie\n" " -d, --del |* usuwa zdarzenie o podanym numerze\n" " można też podać zdarzenie i jego sprawcę\n" " [-l, --list] [numer] wyświetla listę zdarzeń\n" "\n" "Dostępne zdarzenia to:\n" " - avail, away, notavail, dnd, ffc, invisible - zmiana stanu na podany (bez przypadku ,,online'')\n" " - online - zmiana stanu z ,,niedostępny'' na ,,dostępny''\n" " - descr - zmiana opisu\n" " - blocked - zostaliśmy zablokowani\n" " - msg, chat - wiadomość\n" " - query - nowa rozmowa\n" " - conference - nowa konferencja\n" " - delivered - wiadomość została doręczona\n" " - queued - wiadomość została zakolejkowana na serwerze\n" " - filtered - wiadomość została usunięta przez filtry serwera\n" " - mboxfull - odbiorca ma pełną skrzynkę wiadomości\n" " - not_delivered - wiadomość nie została doręczona\n" " - dcc - ktoś przysyła nam plik\n" " - dccfinish - odebrano plik\n" " - image - odebrano obrazek\n" " - sigusr1, sigusr2 - otrzymanie przez ekg danego sygnału\n" " - newmail - otrzymanie nowej wiadomości e-mail\n" " - connected - udało się połączyć z serwerem\n" " - disconnected - serwer nas rozłączył\n" " - connectionlost - utracono połączenie z serwerem\n" "\n" "W przypadku sigusr, newmail, connected, disconnected oraz connectionlost należy podać ,,%T*%n'' " "jako sprawcę zdarzenia.\n" "\n" " - * - wszystkie zdarzenia\n" "\n" "Zdarzenia można łączyć ze sobą za pomocą przecinka lub ,,%T|%n''. Jako numer/alias " "można podać ,,%T*%n'', dzięki czemu zdarzenie będzie dotyczyć każdego użytkownika. " "Jeśli ktoś posiada indywidualną akcję na dane zdarzenie, to tylko ona zostanie " "wykonana. Można podać więcej komend, oddzielając je średnikiem. W komendzie, %T%%1%n " "zostanie zastąpione numerkiem sprawcy zdarzenia, a jeśli istnieje on na naszej " "liście kontaktów, %T%%2%n będzie zastąpione jego pseudonimem. Zamiast %T%%3%n i " "%T%%4%n wpisana będzie treść wiadomości, opis użytkownika, całkowita liczba " "nowych wiadomości e-mail, nazwa pliku, konferencji lub adres serwera - w zależności od zdarzenia. " "Format %T%%4%n różni się od %T%%3%n tym, że wszystkie niebezpieczne znaki, " "które mogłyby zostać zinterpretowane przez shell, zostaną poprzedzone backslashem. " "Używanie %T%%3%n w przypadku komendy ,,exec'' jest %Tniebezpieczne%n. Jeśli naprawdę " "musisz wykorzystać treść wiadomości lub opis, użyj %T\"%%4\"%n (w cudzysłowach)."); command_add ( "passwd", "??", cmd_passwd, 0, " ", "zmienia hasło użytkownika", "\n" "Przed zmianą hasła należy pobrać token komendą %Ttoken%n. Niezbędne " "jest ustawienie zmiennej %Temail%n. Adres e-mail zapisany na serwerze " "zostanie uaktualniony zgodnie z wartością tej zmiennej."); command_add ( "play", "f", cmd_play, 0, " ", "odtwarza plik dźwiękowy", "\n" "Polecenie wymaga zdefiniowania zmiennej %Tsound_app%n"); command_add ( "private", "", cmd_away, 0, " [on/off]", "włącza/wyłącza tryb ,,tylko dla znajomych''", ""); #ifdef WITH_PYTHON command_add ( "python", "p?", cmd_python, 0, " [komenda] [opcje]", "obsługa skryptów", "\n" " exec uruchamia komendę\n" " [list] wyświetla listę załadowanych skryptów\n" " load ładuje skrypt\n" " restart restartuje interpreter\n" " run uruchamia skrypt\n" " unload usuwa skrypt z pamięci\n"); #endif command_add ( "query", "u?", cmd_query, 0, " [wiadomość]", "włącza rozmowę", "\n" "Można podać większą ilość odbiorców oddzielając ich numery lub " "pseudonimy przecinkiem (ale bez odstępów). W takim wypadku " "zostanie rozpoczęta nowa konferencja."); command_add ( "queue", "?u", cmd_queue, 0, " [opcje]", "zarządzanie wiadomościami do wysłania po połączeniu", "\n" " -c, --clear usuwa podane wiadomości lub wszystkie\n" " -u, --user wiadomości dla danego użytkownika\n" "\n" "Można użyć tylko wtedy, gdy nie jesteśmy połączeni. W przypadku " "konferencji wyświetla wszystkich uczestników."); command_add ( "quit", "r", cmd_quit, 0, " [powód/-]", "wychodzi z programu", "\n" "Jeśli włączona jest odpowiednia opcja %Trandom_reason%n i nie " "podano powodu, zostanie wylosowany z pliku %Tquit.reasons%n. " "Podanie ,,%T-%n'' zamiast powodu spowoduje wyczyszczenie bez " "względu na ustawienia zmiennych."); command_add ( "reconnect", "", cmd_connect, 0, "", "rozłącza i łączy ponownie", ""); command_add ( "register", "???", cmd_register, 0, " ", "rejestruje nowe konto", "\n" "Przed rejestracją należy pobrać token komendą %Ttoken%n."); command_add ( "reload", "f", cmd_reload, 0, " [plik]", "wczytuje plik konfiguracyjny użytkownika lub podany", ""); command_add ( "remind", "?", cmd_remind, 0, " ", "wysyła hasło na skrzynkę pocztową", "\n" "Przed operacją należy pobrać token komendą %Ttoken%n."); command_add ( "save", "?", cmd_save, 0, " [plik]", "zapisuje ustawienia programu", "\n" "Aktualny stan zostanie zapisany i będzie przywrócony przy " "następnym uruchomieniu programu. Można podać plik, do którego " "ma być zapisana konfiguracja."); command_add ( "say", "?", cmd_say, 0, " [tekst]", "wymawia tekst", "\n" " -c, --clear usuwa z bufora tekst do wymówienia\n" "\n" "Polecenie wymaga zdefiniowana zmiennej %Tspeech_app%n"); command_add ( "set", "v?", cmd_set, 0, " [-] [[+/-]wartość]", "wyświetla lub zmienia ustawienia", "\n" "Użycie %Tset -zmienna%n czyści zawartość zmiennej. Dla zmiennych " "będących mapami bitowymi można określić, czy wartość ma być " "dodana (poprzedzone plusem), usunięta (minusem) czy ustawiona " "(bez prefiksu). Wartość zmiennej można wziąć w cudzysłów. " "Poprzedzenie opcji parametrem %T-a%n lub %T--all%n spowoduje " "wyświetlenie wszystkich, nawet aktualnie nieaktywnych zmiennych."); command_add ( "sms", "u?", cmd_sms, 0, " ", "wysyła smsa do podanej osoby", "\n" "Polecenie wymaga zdefiniowana zmiennej %Tsms_send_app%n"); command_add ( "status", "", cmd_status, 0, "", "wyświetla aktualny stan", ""); command_add ( "unregister", "???", cmd_register, 0, " ", "usuwa konto z serwera", "\n" "Podanie numeru i hasła jest niezbędne ze względów bezpieczeństwa. " "Nikt nie chciałby chyba usunąć konta przypadkowo, bez żadnego " "potwierdzenia. Przed operacją należy pobrać token komendą " "%Ttoken%n."); command_add ( "conference", "??u", cmd_conference, 0, " [opcje]", "zarządzanie konferencjami", "\n" " -a, --add [#nazwa] tworzy nową konferencję\n" " -j, --join <#nazwa> przyłącza osobę do konferencji\n" " -d, --del <#nazwa>|* usuwa konferencję\n" " -i, --ignore <#nazwa> oznacza konferencję jako ignorowaną\n" " -u, --unignore <#nazwa> oznacza konferencję jako nieignorowaną\n" " -r, --rename <#old> <#new> zmienia nazwę konferencji\n" " -f, --find <#nazwa> wyszukuje uczestników w katalogu\n" " [-l, --list] [#nazwa] wyświetla listę konferencji\n" "\n" "Dodaje nazwę konferencji i definiuje, kto bierze w niej udział. " "Kolejne numery, pseudonimy lub grupy mogą być oddzielone " "przecinkiem lub spacją."); command_add ( "timer", "???c", cmd_timer, 0, " [opcje]", "zarządzanie timerami", "\n" " -a, --add [nazwa] [*/] tworzy nowy timer\n" " -d, --del |* zatrzymuje timer\n" " [-l, --list] [nazwa] wyświetla listę timerów\n" "\n" "Czas, po którym wykonana zostanie komenda, podaje się w sekundach. " "Można też użyć przyrostków %Td%n, %Th%n, %Tm%n, %Ts%n, " "oznaczających dni, godziny, minuty, sekundy, np. 5h20m. Timer po " "jednorazowym uruchomieniu jest usuwany, chyba że czas poprzedzimy " "wyrażeniem ,,%T*/%n''. Wtedy timer będzie uruchamiany w zadanych odstępach " "czasu, a na liście będzie oznaczony gwiazdką."); command_add ( "token", "", cmd_token, 0, "", "pobiera z serwera token", "\n" "Komenda ta jest niezbędna do rejestracji i zmiany hasła. Ma na celu " "zapewnienie serwera, że operację przeprowadza użytkownik, a nie " "automat. Jeśli system zawiera odpowiednie biblioteki, token " "zostanie wyświetlony na ekranie. W przeciwnym wypadku zostanie " "podana ścieżka, pod którą zapisano plik graficzny zawierający " "token. Wyświetlanie tokenu jest eksperymentalne i może być " "konieczne kilkukrotne wydanie komendy. Podczas odczytywania " "może być przydatne ustawienie zmiennej backlog_overlap."); command_add ( "unignore", "i?", cmd_ignore, 0, " |*", "usuwa z listy ignorowanych osób", ""); command_add ( "unblock", "b?", cmd_block, 0, " |*", "usuwa z listy blokowanych osób", ""); command_add ( "version", "", cmd_version, 0, "", "wyświetla wersję programu", ""); command_add ( "window", "w?", cmd_window, 0, " [numer_okna]", "zarządzanie okienkami", "\n" " active przełącza do pierwszego okna,\n" " w którym coś się dzieje\n" " oldest przełącza do najstarszego okna,\n" " w którym coś się dzieje (okna,\n" " które najdłużej jest aktywne)\n" " clear czyści aktualne okno\n" " kill [numer_okna] zamyka aktualne lub podane okno\n" " last przełącza do ostatnio wyświetlanego\n" " okna\n" " list [numer_okna] wyświetla listę okien lub informacje\n" " na temat okna o podanym numerze\n" /* " new [*opcje] tworzy nowe okno\n" */ " new [nazwa] tworzy nowe okno\n" " next przełącza do następnego okna\n" " prev przełącza do poprzedniego okna\n" " switch przełącza do podanego okna\n" " swap zamienia okna miejscami\n" " refresh odświeża aktualne okno\n" " dump zapisuje zawartość okna do pliku"); /* "\n" "Argumenty dla %Tnew%n to %T*x,y,w,h[,f],/komenda%n, gdzie %Tx%n i " "%Ty%n to " "pozycja okna na ekranie, %Tw%n i %Th%n to odpowiednio szerokość " "i wysokość okna w znakach, a %Tf%n jest mapą bitową określającą " "z której strony występują ramki (1 - lewo, 2 - góra, 4 - prawo, " "8 - dół), a komenda określa, jakiej komendy wynik ma być " "wyświetlany regularnie w oknie."); */ command_add ( "_addtab", "??", cmd_test_addtab, 0, "", "dodaje do listy dopełniania TABem", ""); command_add ( "_deltab", "??", cmd_test_deltab, 0, "", "usuwa z listy dopełniania TABem", ""); #if 0 command_add ( "_fds", "", cmd_test_fds, 0, "", "wyświetla otwarte deskryptory", ""); #endif command_add ( "_msg", "u?", cmd_test_send, 0, "", "udaje, że wysyła wiadomość", ""); command_add ( "_hexmsg", "u?", cmd_test_hexmsg, 0, "", "wysyła wiadomość o treści heksadecymalnej", ""); command_add ( "_segv", "", cmd_test_segv, 0, "", "wywołuje naruszenie segmentacji pamięci", ""); command_add ( "_resize", "", cmd_test_resize, 0, "", "dopasowuje wielkość okna do rozmiarów terminala", ""); command_add ( "_ping", "", cmd_test_ping, 0, "", "wysyła pakiet ping do serwera", ""); command_add ( "_watches", "", cmd_test_watches, 0, "", "wyświetla listę sprawdzanych deskryptorów", ""); #ifndef GG_DEBUG_DISABLE command_add ( "_debug", "?", cmd_test_debug, 0, "", "wyświetla tekst w oknie debug", ""); command_add ( "_debug_dump", "", cmd_test_debug_dump, 0, "", "zrzuca debug do pliku", ""); #endif command_add ( "_vars", "", cmd_test_vars, 0, "", "wyświetla skrót zmiennych", ""); command_add ( "_queue", "uu", cmd_queue, 0, " [opcje]", "pozwala obserwować kolejkę wiadomości podczas połączenia", ""); command_add ( "_ctcp", "u", cmd_test_ctcp, 0, " ", "wysyła żądanie bezpośredniego połączenia", ""); command_add ( "_descr", "r", cmd_away, 0, " ", "zmienia opis bez zmiany stanu", ""); command_add ( "_imagereq", "u??", cmd_test_imagereq, 0, " ", "wysyła żądanie wysłania obrazka", "\nSumę kontrolną należy podać w postaci heksadecymalnej."); command_add ( "_imagemsg", "u?", cmd_test_imagemsg, 0, " ", "wysyła wiadomość zawierającą wyłącznie obrazek", ""); command_add ( "_imagesend", "u?", cmd_test_imagesend, 0, " ", "wysyła odpowiedź z obrazkiem", ""); } /* * command_free() * * usuwa listę komend z pamięci. */ void command_free() { list_t l; for (l = commands; l; l = l->next) { struct command *c = l->data; xfree(c->name); xfree(c->params); xfree(c->params_help); xfree(c->brief_help); xfree(c->long_help); } list_destroy(commands, 1); commands = NULL; } ekg-1.9~pre+r2855/src/commands.h000066400000000000000000000042351174410337000163640ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * Dawid Jarosz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __COMMANDS_H #define __COMMANDS_H #include "dynstuff.h" #define printq(x...) do { if (!quiet) { print(x); } } while(0) #define COMMAND(x) int x(const char *name, const char **params, const char *target, int quiet) typedef COMMAND(command_func_t); struct command { char *name; char *params; command_func_t *function; int alias; char *params_help; char *brief_help; char *long_help; }; list_t commands; int change_quiet; int userlist_get_config, userlist_put_config; int command_add(const char *name, const char *params, command_func_t function, int alias, const char *params_help, const char *brief_help, const char *long_help); int command_remove(const char *name); void command_init(void); void command_free(void); int command_exec(const char *target, const char *line, int quiet); int command_exec_format(const char *target, int quiet, const char *format, ...); COMMAND(cmd_alias_exec); COMMAND(cmd_exec); /* * jakaś malutka lista tych, do których były wysyłane wiadomości. */ #define SEND_NICKS_MAX 100 char *send_nicks[SEND_NICKS_MAX]; int send_nicks_count, send_nicks_index; void add_send_nick(const char *nick); void remove_send_nick(const char *nick); int binding_help(int a, int b); int binding_quick_list(int a, int b); int binding_toggle_contacts(int a, int b); int match_arg(const char *arg, char shortopt, const char *longopt, int longoptlen); #endif /* __COMMANDS_H */ ekg-1.9~pre+r2855/src/compat.h000066400000000000000000000016631174410337000160500ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, * USA. */ #ifndef __COMPAT_H #define __COMPAT_H #ifdef sun # define INADDR_NONE ((in_addr_t) 0xffffffff) #endif #endif ekg-1.9~pre+r2855/src/comptime.c000066400000000000000000000014561174410337000163750ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2007 Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "comptime.h" const char *compile_time(void) { return __DATE__ " " __TIME__; } ekg-1.9~pre+r2855/src/comptime.h000066400000000000000000000014501174410337000163740ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2007 Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __COMPTIME_H #define __COMPTIME_H const char *compile_time(void); #endif ekg-1.9~pre+r2855/src/configfile.c000066400000000000000000000327221174410337000166650ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2005 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "commands.h" #include "dynstuff.h" #include "stuff.h" #include "ui.h" #include "vars.h" #include "xmalloc.h" #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif /* * config_read() * * czyta z pliku ~/.gg/config lub podanego konfigurację. * * - filename, * * 0/-1 */ int config_read(const char *filename) { char *buf, *foo; FILE *f; int i = 0, good_file = 0, ret = 1, home = ((filename) ? 0 : 1); struct stat st; if (!filename && !(filename = prepare_path("config", 0))) return -1; if (!(f = fopen(filename, "r"))) return -1; if (stat(filename, &st) || !S_ISREG(st.st_mode)) { if (S_ISDIR(st.st_mode)) errno = EISDIR; else errno = EINVAL; fclose(f); return -1; } gg_debug(GG_DEBUG_MISC, "// config_read();\n"); if (!in_autoexec) { list_t l; for (l = bindings; l; ) { struct binding *b = l->data; l = l->next; if (!b->internal) ui_event("command", 1, "bind", "--del", b->key, NULL, NULL); } alias_free(); timer_remove_user(-1); event_free(); variable_free(); variable_init(); variable_set_default(); gg_debug(GG_DEBUG_MISC, "\tflushed previous config\n"); } while ((buf = read_file(f))) { i++; if (buf[0] == '#' || buf[0] == ';' || (buf[0] == '/' && buf[1] == '/')) { xfree(buf); continue; } foo = unescape(buf); free(buf); buf = foo; if (!(foo = strchr(buf, ' '))) { xfree(buf); continue; } *foo++ = 0; if (!strcasecmp(buf, "set")) { char *bar; if (!(bar = strchr(foo, ' '))) ret = variable_set(foo, NULL, 1); else { *bar++ = 0; ret = variable_set(foo, bar, 1); } if (ret) gg_debug(GG_DEBUG_MISC, "\tunknown variable %s\n", foo); } else if (!strcasecmp(buf, "alias")) { gg_debug(GG_DEBUG_MISC, "\talias %s\n", foo); ret = alias_add(foo, 1, 1); } else if (!strcasecmp(buf, "on")) { int flags; char **pms = array_make(foo, " \t", 3, 1, 0); if (array_count(pms) == 3 && (flags = event_flags(pms[0]))) { gg_debug(GG_DEBUG_MISC, "\ton %s %s %s\n", pms[0], pms[1], pms[2]); ret = event_add(flags, pms[1], pms[2], 1); } array_free(pms); } else if (!strcasecmp(buf, "bind")) { char **pms = array_make(foo, " \t", 2, 1, 0); if (array_count(pms) == 2) { gg_debug(GG_DEBUG_MISC, "\tbind %s %s\n", pms[0], pms[1]); ui_event("command", 1, "bind", "--add", pms[0], pms[1], NULL); } array_free(pms); } else if (!strcasecmp(buf, "at")) { char **p = array_make(foo, " \t", 2, 1, 0); if (array_count(p) == 2) { char *name = NULL, *tmp; gg_debug(GG_DEBUG_MISC, "\tat %s %s\n", p[0], p[1]); if (strcmp(p[0], "(null)")) name = p[0]; tmp = saprintf("/at -a %s %s", ((name) ? name : ""), p[1]); ret = command_exec(NULL, tmp, 1); xfree(tmp); } array_free(p); } else if (!strcasecmp(buf, "timer")) { char **p = array_make(foo, " \t", 3, 1, 0); char *tmp = NULL, *period_str = NULL, *name = NULL; time_t period; if (array_count(p) == 3) { gg_debug(GG_DEBUG_MISC, "\ttimer %s %s %s\n", p[0], p[1], p[2]); if (strcmp(p[0], "(null)")) name = p[0]; if (!strncmp(p[1], "*/", 2)) { period = atoi(p[1] + 2); period_str = saprintf("*/%ld", (long) period); } else { period = atoi(p[1]) - time(NULL); period_str = saprintf("%ld", (long) period); } if (period > 0) { tmp = saprintf("/timer --add %s %s %s", (name) ? name : "", period_str, p[2]); ret = command_exec(NULL, tmp, 1); xfree(tmp); } xfree(period_str); } array_free(p); } else { ret = variable_set(buf, foo, 1); if (ret) gg_debug(GG_DEBUG_MISC, "\tunknown variable %s\n", buf); } if (!ret) good_file = 1; if (!good_file && i > 100) { xfree(buf); break; } xfree(buf); } fclose(f); if (!good_file && !home && !in_autoexec) { config_read(NULL); errno = EINVAL; return -2; } return 0; } /* * config_read_variable() * * czyta z pliku ~/.gg/config jedną zmienną nie interesując się typem, * znaczeniem, ani poprawnością. * * - name - nazwa zmiennej. * * zaalokowany bufor z treścią zmiennej lub NULL, jeśli nie znaleziono. */ char *config_read_variable(const char *name) { const char *filename; char *line; FILE *f; if (!name) return NULL; if (!(filename = prepare_path("config", 0))) return NULL; if (!(f = fopen(filename, "r"))) return NULL; gg_debug(GG_DEBUG_MISC, "// config_read_variable(\"%s\");\n", name); while ((line = read_file(f))) { char *tmp; if (line[0] == '#' || line[0] == ';' || (line[0] == '/' && line[1] == '/')) { xfree(line); continue; } tmp = unescape(line); free(line); line = tmp; if (!(tmp = strchr(line, ' '))) { xfree(line); continue; } *tmp++ = 0; if (!strcasecmp(line, name)) { char *result = xstrdup(tmp); xfree(line); fclose(f); return result; } if (!strcasecmp(line, "set")) { char *foo; if ((foo = strchr(tmp, ' '))) { char *result; *foo++ = 0; result = xstrdup(foo); xfree(line); fclose(f); return result; } } xfree(line); } fclose(f); return NULL; } /* * config_fprintf() * * odpowiednik fprintf() z tym, że przyjmuje jedynie format %s * i eskejpuje znaki: * - \ - zamiana na \\ * - \n - zamiana na literalne \n * - \r - zamiana na literalne \r * * tekst znajdujący się w stringu formatującym nie jest zmieniany. * * interpretowany jest TYLKO format %s. namieszane, bo nie możemy * alokować pamięci. * * - f - plik, do którego piszemy, * - fmt - format, * - reszta - argumenty dla formatu */ void config_fprintf(FILE *f, const char *fmt, ...) { va_list ap; int state = 0; char *str = NULL; va_start(ap, fmt); for (;;) { if (state == 0) { /* normalny tekst */ char ch = *fmt++; if (!ch) break; else if (ch == '%') { state = 1; continue; } fputc(ch, f); } else if (state == 1) { /* eskejpowanie procentem */ if (*fmt++ != 's') { fprintf(stderr, "Wewnętrzny błąd: Niewłaściwy znak w formacie.\n"); exit(EXIT_FAILURE); } str = va_arg(ap, char *); state = 2; } else if (state == 2) { /* string w %s */ char ch = *str++; if (!ch) { state = 0; continue; } else if (ch == '\\') fprintf(f, "\\\\"); else if (ch == '\n') fprintf(f, "\\n"); else if (ch == '\r') fprintf(f, "\\r"); else fputc(ch, f); } } va_end(ap); } /* * config_write_variable() * * zapisuje jedną zmienną do pliku konfiguracyjnego. * * - f - otwarty plik konfiguracji, * - v - wpis zmiennej, * - base64 - czy wolno nam używać base64 i zajmować pamięć? */ void config_write_variable(FILE *f, struct variable *v, int base64) { if (!f || !v || !v->ptr) return; if (v->type == VAR_STR) { if (*(char**)(v->ptr)) { if (!v->display && base64) { char *tmp = base64_encode(*(char**)(v->ptr)); if (config_save_password) config_fprintf(f, "%s \001%s\n", v->name, tmp); xfree(tmp); } else config_fprintf(f, "%s %s\n", v->name, *(char**)(v->ptr)); } } else if (v->type == VAR_FOREIGN) config_fprintf(f, "%s %s\n", v->name, (char*) v->ptr); else fprintf(f, "%s %d\n", v->name, *(int*)(v->ptr)); } /* * config_write_main() * * właściwa funkcja zapisująca konfigurację do podanego pliku. * * - f - plik, do którego piszemy, * - base64 - czy kodować ukryte pola? */ void config_write_main(FILE *f, int base64) { list_t l; if (!f) return; #ifdef WITH_UI_NCURSES if ((config_windows_save & 2) && ui_init == ui_ncurses_init) save_windows(); #endif for (l = variables; l; l = l->next) config_write_variable(f, l->data, base64); for (l = aliases; l; l = l->next) { struct alias *a = l->data; list_t m; for (m = a->commands; m; m = m->next) config_fprintf(f, "alias %s %s\n", a->name, (char*) m->data); } for (l = events; l; l = l->next) { struct event *e = l->data; config_fprintf(f, "on %s %s %s\n", event_format(e->flags), e->target, e->action); } for (l = bindings; l; l = l->next) { struct binding *b = l->data; if (b->internal) continue; config_fprintf(f, "bind %s %s\n", b->key, b->action); } for (l = timers; l; l = l->next) { struct timer *t = l->data; const char *name = NULL; if (t->type != TIMER_COMMAND) continue; /* nie ma sensu zapisywać */ if (!t->persistent && t->ends.tv_sec - time(NULL) < 5) continue; /* posortuje, jeśli nie ma nazwy */ if (t->name && !xisdigit(t->name[0])) name = t->name; else name = "(null)"; if (t->at) { char buf[100]; time_t foo = (time_t) t->ends.tv_sec; struct tm *tt = localtime(&foo); strftime(buf, sizeof(buf), "%G%m%d%H%M.%S", tt); if (t->persistent) config_fprintf(f, "at %s %s/%s %s\n", name, buf, itoa(t->period), t->command); else config_fprintf(f, "at %s %s %s\n", name, buf, t->command); } else { char *foo; if (t->persistent) foo = saprintf("*/%s", itoa(t->period)); else foo = saprintf("%s", itoa(t->ends.tv_sec)); config_fprintf(f, "timer %s %s %s\n", name, foo, t->command); xfree(foo); } } } /* * config_write() * * zapisuje aktualną konfigurację do pliku ~/.gg/config lub podanego. * * 0/-1 */ int config_write(const char *filename) { char tmp[PATH_MAX + 1]; FILE *f; if (!filename && !(filename = prepare_path("config", 1))) return -1; snprintf(tmp, sizeof(tmp), "%s.%d.%ld", filename, (int) getpid(), (long) time(NULL)); if (!(f = fopen(tmp, "w"))) return -1; fchmod(fileno(f), config_files_mode_config); config_write_main(f, 1); if (fclose(f) == EOF) { unlink(tmp); return -1; } if (rename(tmp, filename) == -1) return -1; return 0; } /* * config_write_partly() * * zapisuje podane zmienne, nie zmieniając reszty konfiguracji. * * - vars - tablica z nazwami zmiennych do zapisania. * * 0/-1 */ int config_write_partly(char **vars) { const char *filename; char *newfn, *line; FILE *fi, *fo; int *wrote, i; if (!vars) return -1; if (!(filename = prepare_path("config", 1))) return -1; if (!(fi = fopen(filename, "r"))) return -1; newfn = saprintf("%s.%d.%ld", filename, (int) getpid(), (long) time(NULL)); if (!(fo = fopen(newfn, "w"))) { xfree(newfn); fclose(fi); return -1; } wrote = xcalloc(array_count(vars) + 1, sizeof(int)); fchmod(fileno(fo), config_files_mode_config); while ((line = read_file(fi))) { char *tmp; tmp = unescape(line); free(line); line = tmp; if (line[0] == '#' || line[0] == ';' || (line[0] == '/' && line[1] == '/')) goto pass; if (!strchr(line, ' ')) goto pass; if (!strncasecmp(line, "alias ", 6)) goto pass; if (!strncasecmp(line, "on ", 3)) goto pass; if (!strncasecmp(line, "bind ", 5)) goto pass; tmp = line; if (!strncasecmp(tmp, "set ", 4)) tmp += 4; for (i = 0; vars[i]; i++) { int len = strlen(vars[i]); if (strlen(tmp) < len + 1) continue; if (strncasecmp(tmp, vars[i], len) || tmp[len] != ' ') continue; config_write_variable(fo, variable_find(vars[i]), 1); wrote[i] = 1; xfree(line); line = NULL; break; } if (!line) continue; pass: config_fprintf(fo, "%s\n", line); xfree(line); } for (i = 0; vars[i]; i++) { if (wrote[i]) continue; config_write_variable(fo, variable_find(vars[i]), 1); } xfree(wrote); fclose(fi); if (fclose(fo) == EOF) { unlink(newfn); xfree(newfn); return -1; } if (rename(newfn, filename) == -1) { xfree(newfn); return -1; } xfree(newfn); return 0; } /* * config_write_crash() * * funkcja zapisująca awaryjnie konfigurację. nie powinna alokować żadnej * pamięci. */ void config_write_crash() { char name[32]; FILE *f; chdir(config_dir); snprintf(name, sizeof(name), "config.%d", (int) getpid()); if (!(f = fopen(name, "w"))) return; chmod(name, 0400); config_write_main(f, 0); fclose(f); } /* * debug_write_crash() * * zapisuje ostatnie linie z debug. */ void debug_write_crash() { char name[32]; FILE *f; list_t l; chdir(config_dir); snprintf(name, sizeof(name), "debug.%d", (int) getpid()); if (!(f = fopen(name, "w"))) return; chmod(name, 0400); for (l = buffers; l; l = l->next) { struct buffer *b = l->data; if (b->type == BUFFER_DEBUG) fprintf(f, "%s\n", b->line); } fclose(f); } ekg-1.9~pre+r2855/src/configfile.h000066400000000000000000000023721174410337000166700ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __CONFIGFILE_H #define __CONFIGFILE_H int config_read(const char *filename); char *config_read_variable(const char *var); int config_write(const char *filename); int config_write_partly(char **vars); void config_write_crash(void); void debug_write_crash(void); #endif /* __CONFIGFILE_H */ ekg-1.9~pre+r2855/src/dynstuff.c000066400000000000000000000426761174410337000164330ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2006 Wojtek Kaniewski * Dawid Jarosz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "libgadu.h" #include "dynstuff.h" #include "stuff.h" #include "xmalloc.h" /* * list_add_sorted() * * dodaje do listy dany element. przy okazji może też skopiować zawartość. * jeśli poda się jako ostatni parametr funkcję porównującą zawartość * elementów, może posortować od razu. * * - list - wskaźnik do listy, * - data - wskaźnik do elementu, * - alloc_size - rozmiar elementu, jeśli chcemy go skopiować. * * zwraca wskaźnik zaalokowanego elementu lub NULL w przpadku błędu. */ void *list_add_sorted(list_t *list, void *data, int alloc_size, int (*comparision)(void *, void *)) { list_t new, tmp; if (!list) { errno = EFAULT; return NULL; } new = xmalloc(sizeof(struct list)); new->data = data; new->next = NULL; if (alloc_size) { new->data = xmalloc(alloc_size); memcpy(new->data, data, alloc_size); } if (!(tmp = *list)) { *list = new; } else { if (!comparision) { while (tmp->next) tmp = tmp->next; tmp->next = new; } else { list_t prev = NULL; while (comparision(new->data, tmp->data) > 0) { prev = tmp; tmp = tmp->next; if (!tmp) break; } if (!prev) { tmp = *list; *list = new; new->next = tmp; } else { prev->next = new; new->next = tmp; } } } return new->data; } /* * list_add() * * wrapper do list_add_sorted(), który zachowuje poprzednią składnię. */ void *list_add(list_t *list, void *data, int alloc_size) { return list_add_sorted(list, data, alloc_size, NULL); } /* * list_remove() * * usuwa z listy wpis z podanym elementem. * * - list - wskaźnik do listy, * - data - element, * - free_data - zwolnić pamięć po elemencie. */ int list_remove(list_t *list, void *data, int free_data) { list_t tmp, last = NULL; if (!list) { errno = EFAULT; return -1; } tmp = *list; if (tmp->data == data) { *list = tmp->next; } else { for (; tmp && tmp->data != data; tmp = tmp->next) last = tmp; if (!tmp) { errno = ENOENT; return -1; } last->next = tmp->next; } if (free_data) xfree(tmp->data); xfree(tmp); return 0; } /* * list_count() * * zwraca ilość elementów w danej liście. * * - list - lista. */ int list_count(list_t list) { int count = 0; for (; list; list = list->next) count++; return count; } /* * list_destroy() * * niszczy wszystkie elementy listy. * * - list - lista, * - free_data - czy zwalniać bufor danych? */ int list_destroy(list_t list, int free_data) { list_t tmp; while (list) { if (free_data) xfree(list->data); tmp = list->next; xfree(list); list = tmp; } return 0; } /* * string_realloc() * * upewnia się, że w stringu będzie wystarczająco dużo miejsca. * * - s - ciąg znaków, * - count - wymagana ilość znaków (bez końcowego '\0'). */ static void string_realloc(string_t s, int count) { char *tmp; if (s->str && count + 1 <= s->size) return; tmp = xrealloc(s->str, count + 81); if (!s->str) *tmp = 0; tmp[count + 80] = 0; s->size = count + 81; s->str = tmp; } /* * string_append_c() * * dodaje do danego ciągu jeden znak, alokując przy tym odpowiednią ilość * pamięci. * * - s - ciąg znaków. * - c - znaczek do dopisania. */ int string_append_c(string_t s, char c) { if (!s) { errno = EFAULT; return -1; } string_realloc(s, s->len + 1); s->str[s->len + 1] = 0; s->str[s->len++] = c; return 0; } /* * string_append_n() * * dodaje tekst do bufora alokując odpowiednią ilość pamięci. * * - s - ciąg znaków, * - str - tekst do dopisania, * - count - ile znaków tego tekstu dopisać? (-1 znaczy, że cały). */ int string_append_n(string_t s, const char *str, int count) { if (!s || !str) { errno = EFAULT; return -1; } if (count == -1) count = strlen(str); string_realloc(s, s->len + count); s->str[s->len + count] = 0; strncpy(s->str + s->len, str, count); s->len += count; return 0; } int string_append(string_t s, const char *str) { return string_append_n(s, str, -1); } /* * string_insert_n() * * wstawia tekst w podane miejsce bufora. * * - s - ciąg znaków, * - index - miejsce, gdzie mamy wpisać (liczone od 0), * - str - tekst do dopisania, * - count - ilość znaków do dopisania (-1 znaczy, że wszystkie). */ void string_insert_n(string_t s, int index, const char *str, int count) { if (!s || !str) return; if (count == -1) count = strlen(str); if (index > s->len) index = s->len; string_realloc(s, s->len + count); memmove(s->str + index + count, s->str + index, s->len + 1 - index); memmove(s->str + index, str, count); s->len += count; } void string_insert(string_t s, int index, const char *str) { string_insert_n(s, index, str, -1); } /* * string_init() * * inicjuje strukturę string. alokuje pamięć i przypisuje pierwszą wartość. * * - value - jeśli NULL, ciąg jest pusty, inaczej kopiuje tam. * * zwraca zaalokowaną strukturę `string'. */ string_t string_init(const char *value) { string_t tmp = xmalloc(sizeof(struct string)); if (!value) value = ""; tmp->str = xstrdup(value); tmp->len = strlen(value); tmp->size = strlen(value) + 1; return tmp; } /* * string_clear() * * czyści zawartość struktury `string'. * * - s - ciąg znaków. */ void string_clear(string_t s) { if (!s) return; if (s->size > 160) { s->str = xrealloc(s->str, 80); s->size = 80; } s->str[0] = 0; s->len = 0; } /* * string_free() * * zwalnia pamięć po strukturze string i może też zwolnić pamięć po samym * ciągu znaków. * * - s - struktura, którą wycinamy, * - free_string - zwolnić pamięć po ciągu znaków? * * jeśli free_string=0 zwraca wskaźnik do ciągu, inaczej NULL. */ char *string_free(string_t s, int free_string) { char *tmp = NULL; if (!s) return NULL; if (free_string) xfree(s->str); else tmp = s->str; xfree(s); return tmp; } /* * itoa() * * prosta funkcja, która zwraca tekstową reprezentację liczby. w obrębie * danego wywołania jakiejś funkcji lub wyrażenia może być wywołania 10 * razy, ponieważ tyle mamy statycznych buforów. lepsze to niż ciągłe * tworzenie tymczasowych buforów na stosie i sprintf()owanie. * * - i - liczba do zamiany. * * zwraca adres do bufora, którego _NIE_NALEŻY_ zwalniać. */ const char *itoa(long int i) { static char bufs[10][16]; static int index = 0; char *tmp = bufs[index++]; if (index > 9) index = 0; snprintf(tmp, 16, "%ld", i); return tmp; } /* * array_make() * * tworzy tablicę tekstów z jednego, rozdzielonego podanymi znakami. * * - string - tekst wejściowy, * - sep - lista elementów oddzielających, * - max - maksymalna ilość elementów tablicy. jeśli równe 0, nie ma * ograniczeń rozmiaru tablicy. * - trim - czy większą ilość elementów oddzielających traktować jako * jeden (na przykład spacje, tabulacja itp.) * - quotes - czy pola mogą być zapisywane w cudzysłowiach lub * apostrofach z escapowanymi znakami. * * zaalokowaną tablicę z zaalokowanymi ciągami znaków, którą należy * zwolnić funkcją array_free() */ char **array_make(const char *string, const char *sep, int max, int trim, int quotes) { const char *p, *q; char **result = NULL; int items = 0, last = 0; if (!string || !sep) goto failure; for (p = string; ; ) { int len = 0; char *token = NULL; if (max && items >= max - 1) last = 1; if (trim) { if (*p == '\\') { p++; } else { while (*p && strchr(sep, *p)) p++; if (!*p) break; } } if (!last && quotes && (*p == '\'' || *p == '\"')) { char separ = *p; int meet_quota; for (q = p + 1, len = 0, meet_quota = 0; *q; q++, len++) { if (*q == '\\') { q++; if (!*q) break; } else if (strchr(q, separ)) { meet_quota = 1; } else if (strchr(sep, *q) && meet_quota == 1) break; } if ((token = xcalloc(1, len + 1))) { char *r = token; for (q = p + 1, meet_quota = 0; *q; q++, r++) { if (*q == '\\') { q++; if (!*q) break; switch (*q) { case 'n': *r = '\n'; break; case 'r': *r = '\r'; break; case 't': *r = '\t'; break; default: *r = *q; } } else if (*q == separ) { r--; meet_quota = 1; } else if (strchr(sep, *q) && meet_quota == 1) { break; } else *r = *q; } *r = 0; } p = q; } else { for (q = p, len = 0; *q && (last || !strchr(sep, *q)); q++, len++); token = xcalloc(1, len + 1); strncpy(token, p, len); token[len] = 0; p = q; } result = xrealloc(result, (items + 2) * sizeof(char*)); result[items] = token; result[++items] = NULL; if (!*p) break; p++; } failure: if (!items) result = xcalloc(1, sizeof(char*)); return result; } /* * array_make_quoted() * * tworzy tablicę tekstów z jednego, rozdzielonego podanymi znakami. * różnica w stosunko do array_make() polega na tym, iż array_make nie * zapisuje znaków cudzysłowia w zwracanej tablicy * * - string - tekst wejściowy, * - sep - lista elementów oddzielających, * - max - maksymalna ilość elementów tablicy. jeśli równe 0, nie ma * ograniczeń rozmiaru tablicy. * - trim - czy większą ilość elementów oddzielających traktować jako * jeden (na przykład spacje, tabulacja itp.) * - quotes - czy pola mogą być zapisywane w cudzysłowiach lub * apostrofach z escapowanymi znakami. * * zaalokowaną tablicę z zaalokowanymi ciągami znaków, którą należy * zwolnić funkcją array_free() */ char **array_make_quoted(const char *string, const char *sep, int max, int trim, int quotes) { const char *p, *q; char **result = NULL; int items = 0, last = 0; if (!string || !sep) goto failure; for (p = string; ; ) { int len = 0; char *token = NULL; if (max && items >= max - 1) last = 1; if (trim) { if (*p == '\\') { p++; } else { while (*p && strchr(sep, *p)) p++; if (!*p) break; } } if (!last && quotes && (*p == '\'' || *p == '\"')) { char separ = *p; int meet_quota; for (q = p + 1, len = 0, meet_quota = 0; *q; q++, len++) { if (*q == '\\') { q++; if (!*q) break; } else if (strchr(q, separ)) { meet_quota = 1; } else if (strchr(sep, *q) && meet_quota == 1) break; } len++; if ((token = xcalloc(1, len + 1))) { char *r = token; for (q = p + 1, meet_quota = 0, *r = *p, r++; *q; q++, r++) { if (*q == '\\') { q++; if (!*q) break; switch (*q) { case 'n': *r = '\n'; break; case 'r': *r = '\r'; break; case 't': *r = '\t'; break; default: *r = *q; } } else if (*q == separ) { *r = *q; meet_quota = 1; } else if (strchr(sep, *q) && meet_quota == 1) { break; } else *r = *q; } *r = 0; } //p = (*q) ? q + 1 : q; p = q; } else { for (q = p, len = 0; *q && (last || !strchr(sep, *q)); q++, len++); token = xcalloc(1, len + 1); strncpy(token, p, len); token[len] = 0; p = q; } result = xrealloc(result, (items + 2) * sizeof(char*)); result[items] = token; result[++items] = NULL; if (!*p) break; p++; } failure: if (!items) result = xcalloc(1, sizeof(char*)); return result; } /* * array_count() * * zwraca ilość elementów tablicy. */ int array_count(char **array) { int result = 0; if (!array) return 0; while (*array) { result++; array++; } return result; } /* * array_add() * * dodaje element do tablicy. */ void array_add(char ***array, char *string) { int count = array_count(*array); *array = xrealloc(*array, (count + 2) * sizeof(char*)); (*array)[count + 1] = NULL; (*array)[count] = string; } /* * array_join() * * łączy elementy tablicy w jeden string oddzielając elementy odpowiednim * separatorem. * * - array - wskaźnik do tablicy, * - sep - seperator. * * zwrócony ciąg znaków należy zwolnić. */ char *array_join(char **array, const char *sep) { string_t s = string_init(NULL); int i; if (!array) return xstrdup(""); for (i = 0; array[i]; i++) { if (i) string_append(s, sep); string_append(s, array[i]); } return string_free(s, 0); } /* * array_item_contains() * * stwierdza czy w tablicy znajduje się element zawierający podany ciąg * * - array - tablica, * - string - szukany ciąg znaków, * - casesensitive - czy mamy zwracać uwagę na wielkość znaków? * * 0/1 */ int array_item_contains(char **array, const char *string, int casesensitive) { int i; if (!array || !string) return 0; for (i = 0; array[i]; i++) { if (casesensitive && strstr(array[i], string)) return 1; if (!casesensitive && strcasestr(array[i], string)) return 1; } return 0; } /* * array_add_check() * * dodaje element do tablicy, uprzednio sprawdzając * czy taki już w niej nie istnieje * * - array - tablica, * - string - szukany ciąg znaków, * - casesensitive - czy mamy zwracać uwagę na wielkość znaków? */ void array_add_check(char ***array, char *string, int casesensitive) { if (!array_item_contains(*array, string, casesensitive)) array_add(array, string); else xfree(string); } /* * array_contains() * * stwierdza, czy tablica zawiera podany element. * * - array - tablica, * - string - szukany ciąg znaków, * - casesensitive - czy mamy zwracać uwagę na wielkość znaków? * * 0/1 */ int array_contains(char **array, const char *string, int casesensitive) { int i; if (!array || !string) return 0; for (i = 0; array[i]; i++) { if (casesensitive && !strcmp(array[i], string)) return 1; if (!casesensitive && !strcasecmp(array[i], string)) return 1; } return 0; } /* * array_free() * * zwalnia pamieć zajmowaną przez tablicę. */ void array_free(char **array) { char **tmp; if (!array) return; for (tmp = array; *tmp; tmp++) xfree(*tmp); xfree(array); } /* * eskejpuje: * * - \ -> \\ * * oraz wystąpienia znaków ze stringa esc: * * - 0x07 (\a) -> \a * - 0x08 (\b) -> \b * - 0x09 (\t) -> \t * - 0x0A (\n) -> \n * - 0x0B (\v) -> \v * - 0x0C (\f) -> \f * - 0x0D (\r) -> \r * - pozostałe -> \xXX (szesnastkowa reprezentacja) * * jeżeli któryś z wymienionych wyżej znaków (np. \a) nie występuje * w stringu to zostanie przepisany tak jak jest, bez eskejpowania. * * zwraca nowego, zaalokowanego stringa. */ char *escape(const char *src, const char *esc) { string_t dst; if (!src) return NULL; dst = string_init(NULL); for (; *src; src++) { char ch = *src; static const char esctab[] = "abtnvfr"; if (!(ch == '\\' || strchr(esc, ch))) { string_append_c(dst, ch); continue; } string_append_c(dst, '\\'); if (ch >= 0x07 && ch <= 0x0D) string_append_c(dst, esctab[ch - 0x07]); else if (ch == '\\') string_append_c(dst, '\\'); else { char s[5]; snprintf(s, sizeof(s), "x%02X", (unsigned char) ch); string_append(dst, s); } } return string_free(dst, 0); } /* * dekoduje stringa wyeskejpowanego przy pomocy escape. * * - \\ -> \ * - \xXX -> szesnastkowo zdekodowany znak * - \cokolwiekinnego -> \cokolwiekinnego * * zwraca nowego, zaalokowanego stringa. */ char *unescape(const char *src) { int state = 0; string_t buf; unsigned char hex_msb = 0; if (!src) return NULL; buf = string_init(NULL); for (; *src; src++) { char ch = *src; if (state == 0) { /* normalny tekst */ /* sprawdzamy czy mamy cos po '\\', bo jezeli to ostatni * znak w stringu, to nie zostanie nigdy dodany. */ if (ch == '\\' && *(src + 1)) { state = 1; continue; } string_append_c(buf, ch); } else if (state == 1) { /* kod ucieczki */ if (ch == 'a') ch = '\a'; else if (ch == 'b') ch = '\b'; else if (ch == 't') ch = '\t'; else if (ch == 'n') ch = '\n'; else if (ch == 'v') ch = '\v'; else if (ch == 'f') ch = '\f'; else if (ch == 'r') ch = '\r'; else if (ch == 'x' && *(src + 1) && *(src + 2)) { state = 2; continue; } else if (ch != '\\') string_append_c(buf, '\\'); /* fallback - nieznany kod */ string_append_c(buf, ch); state = 0; } else if (state == 2) { /* pierwsza cyfra kodu szesnastkowego */ hex_msb = ch; state = 3; } else if (state == 3) { /* druga cyfra kodu szesnastkowego */ #define unhex(x) (unsigned char) ((x >= '0' && x <= '9') ? (x - '0') : \ (x >= 'A' && x <= 'F') ? (x - 'A' + 10) : \ (x >= 'a' && x <= 'f') ? (x - 'a' + 10) : 0) string_append_c(buf, unhex(ch) | (unhex(hex_msb) << 4)); #undef unhex state = 0; } } return string_free(buf, 0); } ekg-1.9~pre+r2855/src/dynstuff.h000066400000000000000000000050121174410337000164170ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2006 Wojtek Kaniewski * Dawid Jarosz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __DYNSTUFF_H #define __DYNSTUFF_H /* listy */ struct list { void *data; struct list *next; }; typedef struct list * list_t; void *list_add(list_t *list, void *data, int alloc_size); void *list_add_sorted(list_t *list, void *data, int alloc_size, int (*comparision)(void *, void *)); int list_remove(list_t *list, void *data, int free_data); int list_count(list_t list); int list_destroy(list_t list, int free_data); /* stringi */ struct string { char *str; int len, size; }; typedef struct string * string_t; string_t string_init(const char *str); int string_append(string_t s, const char *str); int string_append_n(string_t s, const char *str, int count); int string_append_c(string_t s, char ch); void string_insert(string_t s, int index, const char *str); void string_insert_n(string_t s, int index, const char *str, int count); void string_clear(string_t s); char *string_free(string_t s, int free_string); /* tablice stringów */ char **array_make(const char *string, const char *sep, int max, int trim, int quotes); char **array_make_quoted(const char *string, const char *sep, int max, int trim, int quotes); char *array_join(char **array, const char *sep); void array_add(char ***array, char *string); void array_add_check(char ***array, char *string, int casesensitive); int array_item_contains(char **array, const char *string, int casesensitive); int array_count(char **array); int array_contains(char **array, const char *string, int casesensitive); void array_free(char **array); /* rozszerzenia libców */ const char *itoa(long int i); /* inne funkcje pomocnicze */ char *escape(const char *src, const char *esc); char *unescape(const char *src); #endif /* __DYNSTUFF_H */ ekg-1.9~pre+r2855/src/ekg.c000066400000000000000000001210611174410337000153210ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2005 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Adam Osuchowski * Dawid Jarosz * Wojciech Bojdoł * Piotr Domagalski * Piotr Kupisiewicz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LOCALE_H # include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_EXECINFO_H # include #endif #include "commands.h" #include "configfile.h" #include "emoticons.h" #include "events.h" #include "libgadu.h" #include "log.h" #include "mail.h" #include "msgqueue.h" #ifdef HAVE_OPENSSL # include "simlite.h" #endif #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "userlist.h" #include "vars.h" #include "version.h" #include "xmalloc.h" #ifdef WITH_PYTHON # include "python.h" #endif #include "comptime.h" #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif static pid_t ekg_pid = 0; static char argv0[PATH_MAX + 1]; static int ioctld_pid = 0; time_t last_action = 0; char *pipe_file = NULL; pid_t speech_pid = 0; static void get_line_from_pipe(struct gg_exec *c); static int get_char_from_pipe(struct gg_common *c); int old_stderr = 0; static volatile sig_atomic_t do_exit = 0; static volatile sig_atomic_t do_handle_sigusr1 = 0; static volatile sig_atomic_t do_handle_sigusr2 = 0; static char sigsegv_msg[1024]; /* * usuwanie sesji GG_SESSION_USERx. wystarczy zwolnić. */ static void reaper_user(void *foo) { xfree(foo); } /* * usuwanie sesji GG_SESSION_USER3. trzeba wcześniej zwolnić pola sesji. */ static void reaper_user3(struct gg_exec *e) { if (e->buf) string_free(e->buf, 1); if (e->target) xfree(e->target); xfree(e); } /* * struktura zawierająca adresy funkcji obsługujących różne sesje * i zwalniających pamięć po nich. */ static struct { int type; void (*handler)(void*); void (*reaper)(void*); } handlers[] = { #define EKG_HANDLER(x, y, z) { x, (void(*)(void*)) y, (void(*)(void*)) z }, EKG_HANDLER(GG_SESSION_GG, handle_event, gg_free_session) EKG_HANDLER(GG_SESSION_DCC, handle_dcc, gg_dcc_free) EKG_HANDLER(GG_SESSION_DCC_SOCKET, handle_dcc, gg_dcc_free) EKG_HANDLER(GG_SESSION_DCC_SEND, handle_dcc, gg_dcc_free) EKG_HANDLER(GG_SESSION_DCC_GET, handle_dcc, gg_dcc_free) EKG_HANDLER(GG_SESSION_DCC_VOICE, handle_dcc, gg_dcc_free) EKG_HANDLER(GG_SESSION_DCC7_SOCKET, handle_dcc7, gg_dcc7_free) EKG_HANDLER(GG_SESSION_DCC7_SEND, handle_dcc7, gg_dcc7_free) EKG_HANDLER(GG_SESSION_DCC7_GET, handle_dcc7, gg_dcc7_free) EKG_HANDLER(GG_SESSION_DCC7_VOICE, handle_dcc7, gg_dcc7_free) EKG_HANDLER(GG_SESSION_REGISTER, handle_pubdir, gg_register_free) EKG_HANDLER(GG_SESSION_UNREGISTER, handle_pubdir, gg_pubdir_free) EKG_HANDLER(GG_SESSION_PASSWD, handle_pubdir, gg_change_passwd_free) EKG_HANDLER(GG_SESSION_REMIND, handle_pubdir, gg_remind_passwd_free) EKG_HANDLER(GG_SESSION_TOKEN, handle_token, gg_token_free) EKG_HANDLER(GG_SESSION_USER0, NULL, reaper_user) /* stdin */ EKG_HANDLER(GG_SESSION_USER1, get_char_from_pipe, reaper_user) /* control pipe */ EKG_HANDLER(GG_SESSION_USER2, handle_voice, reaper_user) /* voice */ EKG_HANDLER(GG_SESSION_USER3, get_line_from_pipe, reaper_user3) /* exec, stderr */ EKG_HANDLER(GG_SESSION_USER4, get_line_from_pipe, reaper_user3) /* mail */ #undef EKG_HANDLER { -1, NULL, NULL } }; /* * get_char_from_pipe() * * funkcja pobiera z potoku sterującego znak do bufora, a gdy się zapełni * bufor wykonuje go tak jakby tekst w buforze wpisany był z terminala. * * - c - struktura sterująca przechowująca m.in. deskryptor potoku. * * 0/-1 */ static int get_char_from_pipe(struct gg_common *c) { static char buf[2048]; static int escaped; char ch; if (!c) return -1; if (read(c->fd, &ch, 1) == -1) return -1; if (ch != '\n' && ch != '\r') { if (strlen(buf) < sizeof(buf) - 2) buf[strlen(buf)] = ch; } if (ch == '\n' && escaped) { /* zamazuje \\ */ strcpy(buf + strlen(buf) - 1, "\r\n"); } if ((ch == '\n' && !escaped) || (strlen(buf) >= sizeof(buf) - 2)) { command_exec(NULL, buf, 0); memset(buf, 0, sizeof(buf)); ui_event("refresh_time", NULL); } if (ch == '\\') { escaped = 1; } else if (ch != '\r' && ch != '\n') { escaped = 0; } return 0; } /* * get_line_from_pipe() * * funkcja pobiera z potoku sterującego znak do bufora, a gdy dojdzie * do konca linii puszcza na ekran. * * - c - struktura sterująca przechowująca m.in. deskryptor potoku. */ static void get_line_from_pipe(struct gg_exec *c) { char buf[8192]; int ret; if (!c) return; if ((ret = read(c->fd, buf, sizeof(buf) - 1)) != 0 && ret != -1) { char *tmp, *tab; buf[ret] = 0; string_append(c->buf, buf); while ((tab = strchr(c->buf->str, '\t'))) { int count; char *last_n = tab; *tab = ' '; while (*last_n) { if (*last_n == '\n') break; else last_n--; } count = 8 - ((int) (tab - last_n)) % 8; if (count > 1) string_insert_n(c->buf, (tab - c->buf->str), " ", count - 1); } while ((tmp = strchr(c->buf->str, '\n'))) { int index = tmp - c->buf->str; char *line = xstrmid(c->buf->str, 0, index); string_t new; if (strlen(line) > 1 && line[strlen(line) - 1] == '\r') line[strlen(line) - 1] = 0; if (c->type == GG_SESSION_USER4) { check_mail_update(line, 1); } else if (!c->quiet) { switch (c->msg) { case 0: print_window(c->target, 0, "exec", line, itoa(c->id)); break; case 1: if (*line) { char *tmp = saprintf("/chat \"%s\" %s", c->target, line); command_exec(NULL, tmp, 0); xfree(tmp); } break; case 2: buffer_add(BUFFER_EXEC, c->target, line, 0); break; } } new = string_init(c->buf->str + index + 1); string_free(c->buf, 1); c->buf = new; xfree(line); } } if ((ret == -1 && errno != EAGAIN) || ret == 0) { if (c->buf->len) { if (c->type == GG_SESSION_USER4) { check_mail_update(c->buf->str, 0); } else if (!c->quiet) { switch (c->msg) { case 0: print_window(c->target, 0, "exec", c->buf->str, itoa(c->id)); break; case 1: if (*(c->buf->str)) { char *tmp = saprintf("/chat \"%s\" %s", c->target, c->buf->str); command_exec(NULL, tmp, 0); xfree(tmp); } break; case 2: buffer_add(BUFFER_EXEC, c->target, c->buf->str, 0); break; } } } if (!c->quiet && c->msg == 2) { char *out = buffer_flush(BUFFER_EXEC, c->target); if (*out) { char *tmp = saprintf("/chat \"%s\" %s", c->target, out); command_exec(NULL, tmp, 0); xfree(tmp); } xfree(out); } close(c->fd); xfree(c->target); string_free(c->buf, 1); list_remove(&watches, c, 1); } } /* * ekg_wait_for_key() * * funkcja wywoływana przez interfejsy użytkownika do przetwarzania danych * z sieci, gdy czeka się na reakcję użytkownika. obsługuje timery, * timeouty i wszystko, co ma się dziać w tle. */ void ekg_wait_for_key() { static time_t last_ping = 0; static time_t last_spied_check = 0; struct timeval tv; list_t l, m; fd_set rd, wd; int ret, maxfd, pid, status; #ifdef WITH_WAP static int wap_userlist_timer = 0; #endif for (;;) { /* przejrzyj timery użytkownika, ui, skryptów */ for (l = timers; l; ) { struct timer *t = l->data; struct timeval tv; struct timezone tz; l = l->next; gettimeofday(&tv, &tz); if (tv.tv_sec > t->ends.tv_sec || (tv.tv_sec == t->ends.tv_sec && tv.tv_usec >= t->ends.tv_usec)) { char *command = xstrdup(t->command), *id = xstrdup(t->id); int type = t->type; if (!t->persistent) { xfree(t->name); xfree(t->command); xfree(t->id); list_remove(&timers, t, 1); } else { struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); tv.tv_sec += t->period; memcpy(&t->ends, &tv, sizeof(tv)); } switch (type) { case TIMER_SCRIPT: #ifdef WITH_PYTHON python_function(command, id); #endif break; case TIMER_UI: ui_event(command, NULL); break; default: command_exec(NULL, command, 0); } xfree(command); xfree(id); } } /* sprawdź timeouty różnych sesji */ for (l = watches; l; l = l->next) { struct gg_session *s = l->data; struct gg_common *c = l->data; struct gg_http *h = l->data; struct gg_dcc *d = l->data; struct gg_dcc7 *d7 = l->data; static time_t last_check = 0; if (!c || c->timeout == -1 || time(NULL) == last_check) continue; last_check = time(NULL); c->timeout--; if (c->timeout > 0) continue; switch (c->type) { case GG_SESSION_GG: if (c->state == GG_STATE_CONNECTING_GG) { /* w przypadku timeoutu nie * wyrzucamy połączenia z listy * tylko każemy mu stwierdzić * błąd i połączyć się z * kolejnym kandydatem. */ handle_event((struct gg_session*) c); } else { print("conn_timeout"); list_remove(&watches, s, 0); gg_logoff(s); gg_free_session(s); userlist_clear_status(0); sess = NULL; ekg_reconnect(); } break; case GG_SESSION_REGISTER: print("register_timeout"); list_remove(&watches, h, 0); gg_free_pubdir(h); xfree(reg_password); reg_password = NULL; xfree(reg_email); reg_email = NULL; break; case GG_SESSION_UNREGISTER: print("unregister_timeout"); list_remove(&watches, h, 0); gg_free_pubdir(h); break; case GG_SESSION_PASSWD: print("passwd_timeout"); list_remove(&watches, h, 0); gg_free_pubdir(h); xfree(reg_password); reg_password = NULL; xfree(reg_email); reg_email = NULL; break; case GG_SESSION_REMIND: print("remind_timeout"); list_remove(&watches, h, 0); gg_free_pubdir(h); break; case GG_SESSION_DCC: case GG_SESSION_DCC_GET: case GG_SESSION_DCC_SEND: { struct in_addr addr; unsigned short port = d->remote_port; char *tmp; addr.s_addr = d->remote_addr; if (d->peer_uin) { struct userlist *u = userlist_find(d->peer_uin, NULL); if (!addr.s_addr && u) { addr.s_addr = u->ip.s_addr; port = u->port; } tmp = saprintf("%s (%s:%d)", format_user(d->peer_uin), inet_ntoa(addr), port); } else tmp = saprintf("%s:%d", inet_ntoa(addr), port); print("dcc_timeout", tmp); xfree(tmp); remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); break; } case GG_SESSION_DCC7_GET: case GG_SESSION_DCC7_SEND: { struct in_addr addr; unsigned short port = d7->remote_port; char *tmp; addr.s_addr = d7->remote_addr; if (d7->peer_uin) { struct userlist *u = userlist_find(d7->peer_uin, NULL); if (!addr.s_addr && u) { addr.s_addr = u->ip.s_addr; port = u->port; } tmp = saprintf("%s (%s:%d)", format_user(d7->peer_uin), inet_ntoa(addr), port); } else tmp = saprintf("%s:%d", inet_ntoa(addr), port); print("dcc_timeout", tmp); xfree(tmp); remove_transfer(d7); list_remove(&watches, d7, 0); gg_dcc7_free(d7); break; } } break; } /* timeout reconnectu */ if (!sess && reconnect_timer && time(NULL) - reconnect_timer >= config_auto_reconnect && config_uin && config_password) { reconnect_timer = 0; print("connecting"); connecting = 1; ekg_connect(); } /* timeout pinga */ if (sess && sess->state == GG_STATE_CONNECTED && time(NULL) - last_ping > 60) { if (last_ping) gg_ping(sess); last_ping = time(NULL); } /* timeout autoawaya */ if (config_auto_away && GG_S_A(config_status) && time(NULL) - last_action > config_auto_away && sess && sess->state == GG_STATE_CONNECTED) { change_status(GG_STATUS_BUSY, (config_auto_away_keep_descr) ? config_reason : NULL, 1); in_auto_away = 1; } /* auto save */ if (config_auto_save && config_changed && time(NULL) - last_save > config_auto_save) { gg_debug(GG_DEBUG_MISC, "-- autosaving userlist and config after %d seconds.\n", time(NULL) - last_save); last_save = time(NULL); if (!userlist_write(0) && !config_write(NULL)) { config_changed = 0; print("autosaved"); } else print("error_saving"); } /* co sekundę sprawdź timeouty podglądanych osób */ if (time(NULL) != last_spied_check) { list_t l; last_spied_check = time(NULL); for (l = spiedlist; l; ) { struct spied *s = l->data; l = l->next; if (s->timeout == -1) continue; s->timeout--; if (s->timeout == 0) { struct userlist *u = userlist_find(s->uin, NULL); char *tmp = NULL; time_t tmp_seen = 0; int correct_seen = 0; if (!u) { list_remove(&spiedlist, s, 1); continue; } gg_debug(GG_DEBUG_MISC, "// ekg: spying %d timeout\n", s->uin); /* wymuś pokazanie zmiany na niedostępny */ if (GG_S_NA(u->status)) { if (config_events_delay && (time(NULL) - (last_conn_event + SPYING_RESPONSE_TIMEOUT)) < config_events_delay) { s->timeout = -1; continue; } u->status = (GG_S_D(u->status)) ? GG_STATUS_INVISIBLE_DESCR : GG_STATUS_INVISIBLE; if (u->last_descr) tmp = xstrdup(u->last_descr); u->ip = u->last_ip; u->port = u->last_port; tmp_seen = u->last_seen; correct_seen = 1; } if (GG_S_I(u->status)) { int status = (GG_S_D(u->status)) ? GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL; iso_to_cp((unsigned char *) u->descr); handle_common(u->uin, status, u->descr, time(NULL), u->ip.s_addr, u->port, u->protocol, u->image_size); if (tmp) { xfree(u->last_descr); u->last_descr = tmp; } if (correct_seen) u->last_seen = tmp_seen; } s->timeout = -1; } } } #ifdef WITH_WAP /* co jakiś czas zrzuć userlistę dla frontendu wap */ if (!wap_userlist_timer) wap_userlist_timer = time(NULL); if (wap_userlist_timer + 60 > time(NULL)) { userlist_write_wap(); wap_userlist_timer = time(NULL); } #endif /* dostaliśmy sygnał, wracamy do ui */ if (ui_need_refresh) break; /* zerknij na wszystkie niezbędne deskryptory */ FD_ZERO(&rd); FD_ZERO(&wd); for (maxfd = 0, l = watches; l; l = l->next) { struct gg_common *w = l->data; if (!w || w->state == GG_STATE_ERROR || w->state == GG_STATE_IDLE || w->state == GG_STATE_DONE) continue; if (w->fd > maxfd) maxfd = w->fd; if ((w->check & GG_CHECK_READ)) FD_SET(w->fd, &rd); if ((w->check & GG_CHECK_WRITE)) FD_SET(w->fd, &wd); } #ifdef WITH_UI_GTK if (ui_init == ui_gtk_init) { tv.tv_sec = 0; tv.tv_usec = 20000; } else #endif { /* domyślny timeout to 1s */ tv.tv_sec = 1; tv.tv_usec = 0; } /* ale jeśli któryś timer ma wystąpić wcześniej niż za sekundę * to skróćmy odpowiednio czas oczekiwania */ for (l = timers; l; l = l->next) { struct timer *t = l->data; struct timeval tv2; struct timezone tz; int usec = 0; gettimeofday(&tv2, &tz); /* żeby uniknąć przekręcenia licznika mikrosekund przy * większych czasach, pomijamy długie timery */ if (t->ends.tv_sec - tv2.tv_sec > 5) continue; /* zobacz, ile zostało do wywołania timera */ usec = (t->ends.tv_sec - tv2.tv_sec) * 1000000 + (t->ends.tv_usec - tv2.tv_usec); /* jeśli więcej niż sekunda, to nie ma znacznia */ if (usec >= 1000000) continue; /* jeśli mniej niż aktualny timeout, zmniejsz */ if (tv.tv_sec * 1000000 + tv.tv_usec > usec) { tv.tv_sec = 0; tv.tv_usec = usec; } } /* na wszelki wypadek sprawdź wartości */ if (tv.tv_sec < 0) tv.tv_sec = 0; if (tv.tv_usec < 0) tv.tv_usec = 0; /* sprawdź, co się dzieje */ ret = select(maxfd + 1, &rd, &wd, NULL, &tv); { sigset_t sigset_usr; int do_continue = 0; sigemptyset(&sigset_usr); sigaddset(&sigset_usr, SIGUSR1); sigaddset(&sigset_usr, SIGUSR2); sigprocmask(SIG_BLOCK, &sigset_usr, NULL); if (do_handle_sigusr1) { /* * dzięki blokadzie, w tym momencie nie * stracimy sygnału. mimo wszystko i tak * obsługa sygnałów jest słaba -- w czasie * jednej iteracji głównej pętli obsłużymy * sygnał maksymalnie jeden raz, niezależnie od * faktyczniej liczby wystąpień. */ do_handle_sigusr1 = 0; event_check(EVENT_SIGUSR1, 0, "SIGUSR1"); ui_event("refresh_time", NULL); do_continue = 1; } if (do_handle_sigusr2) { do_handle_sigusr2 = 0; event_check(EVENT_SIGUSR2, 0, "SIGUSR2"); ui_event("refresh_time", NULL); do_continue = 1; } sigprocmask(SIG_UNBLOCK, &sigset_usr, NULL); if (do_continue) continue; } if (do_exit) ekg_exit(); /* jeśli wystąpił błąd, daj znać */ if (ret == -1) { if (errno != EINTR) perror("select()"); continue; } /* nic się nie stało? jeśli to tryb wsadowy i zrobiliśmy, * co mieliśmy zrobić, wyjdź. */ if (!ret) { if (batch_mode && !batch_line) break; #ifdef WITH_UI_GTK if (ui_init == ui_gtk_init) break; #endif continue; } /* przejrzyj deskryptory */ for (l = watches; l; l = l->next) { struct gg_common *c = l->data; int i; if (!c || (!FD_ISSET(c->fd, &rd) && !FD_ISSET(c->fd, &wd))) continue; if (c->type == GG_SESSION_USER0) { if (config_auto_back == 2 && GG_S_B(config_status) && in_auto_away) { change_status(GG_STATUS_AVAIL, (config_auto_away_keep_descr) ? config_reason : NULL, 1); in_auto_away = 0; } if (config_auto_back == 2) unidle(); return; } /* obsługujemy poza listą handlerów, ponieważ może * zwrócić błąd w przypadku błędu. wtedy grzecznie * usuwamy z listy deskryptorów. */ if (c->type == GG_SESSION_USER1) { if (get_char_from_pipe(c)) list_remove(&watches, c, 1); } for (i = 0; handlers[i].type != -1; i++) if (c->type == handlers[i].type && handlers[i].handler) { (handlers[i].handler)(c); break; } if (handlers[i].type == -1) { list_remove(&watches, c, 1); break; } break; } /* przeglądanie zdechłych dzieciaków */ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { for (l = children; l; l = m) { struct process *p = l->data; m = l->next; if (pid != p->pid) continue; if (pid == speech_pid) { speech_pid = 0; if (!config_speech_app) xfree(buffer_flush(BUFFER_SPEECH, NULL)); if (buffer_count(BUFFER_SPEECH) && !(WEXITSTATUS(status))) { char *str = buffer_tail(BUFFER_SPEECH); say_it(str); xfree(str); } } switch (p->name[0]) { case '\001': print((!(WEXITSTATUS(status))) ? "sms_sent" : "sms_failed", p->name + 1); xfree(p->name); list_remove(&children, p, 1); break; default: p->died = 1; break; } } } for (l = children; l; l = m) { struct process *p = l->data; m = l->next; if (p->died) { int left = 0; #ifdef FIONREAD list_t l; int fd = -1; for (l = watches; l; l = l->next) { struct gg_common *c = l->data; if (c->type == GG_SESSION_USER3 && c->id == p->pid) { fd = c->fd; break; } } if (fd > 0) ioctl(fd, FIONREAD, &left); #endif if (!left) { if (p->name[0] != '\002' && p->name[0] != '\003') print("process_exit", itoa(p->pid), p->name, itoa(WEXITSTATUS(status))); xfree(p->name); list_remove(&children, p, 1); } } } } return; } static void handle_sigusr1(int sig) { do_handle_sigusr1 = 1; } static void handle_sigusr2(int sig) { do_handle_sigusr2 = 1; } static void handle_sighup(int sig) { do_exit = 1; } /* * ioctld_kill() * * zajmuje się usunięciem ioctld z pamięci. */ static void ioctld_kill() { if (ioctld_pid > 0 && ekg_pid == getpid()) kill(ioctld_pid, SIGINT); } #ifdef HAVE_BACKTRACE static void dump_stack(void) { char name[32]; void *frames[64]; size_t sz; int fd; if (chdir(config_dir) == -1) return; snprintf(name, sizeof(name), "stack.%d", (int) getpid()); if ((fd = open(name, O_CREAT | O_WRONLY, 0400)) == -1) return; sz = backtrace(frames, sizeof(frames) / sizeof(*frames)); backtrace_symbols_fd(frames, sz, fd); close(fd); } #endif static void handle_sigsegv(int sig) { static int killing_ui = 0; static struct sigaction sa; ioctld_kill(); if (!killing_ui) { killing_ui = 1; ui_deinit(); } if (old_stderr) dup2(old_stderr, 2); write(2, sigsegv_msg, strlen(sigsegv_msg) + 1); config_write_crash(); userlist_write_crash(); debug_write_crash(); #ifdef HAVE_BACKTRACE dump_stack(); #endif memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sigaction(sig, &sa, NULL); kill(getpid(), sig); } /* * prepare_batch_line() * * funkcja bierze podane w linii poleceń argumenty i robi z nich pojedyńczą * linię poleceń. * * - argc - wiadomo co ;) * - argv - wiadomo co ;) * - n - numer argumentu od którego zaczyna się polecenie. * * zwraca stworzoną linie w zaalokowanym buforze lub NULL przy błędzie. */ static char *prepare_batch_line(int argc, char *argv[], int n) { size_t len = 0; char *buf; int i; for (i = n; i < argc; i++) len += strlen(argv[i]) + 1; buf = xmalloc(len); for (i = n; i < argc; i++) { strlcat(buf, argv[i], len); if (i < argc - 1) strlcat(buf, " ", len); } return buf; } #ifndef GG_DEBUG_DISABLE /* * debug_handler() * * obsługuje informacje debugowania libgadu i klienta. */ static void debug_handler(int level, const char *format, va_list ap) { static string_t line = NULL; char *tmp; char *theme_format; tmp = gg_vsaprintf(format, ap); if (line) { string_append(line, tmp); xfree(tmp); tmp = NULL; if (line->str[strlen(line->str) - 1] == '\n') { tmp = string_free(line, 0); line = NULL; } } else { if (tmp[strlen(tmp) - 1] != '\n') { line = string_init(tmp); xfree(tmp); tmp = NULL; } } if (!tmp) return; switch(level) { /* nieuzywane? */ /* case GG_DEBUG_NET 1: theme_format = "debug"; break; */ case /* GG_DEBUG_TRAFFIC */ 2: theme_format = "iodebug"; break; case /* GG_DEBUG_DUMP */ 4: theme_format = "iodebug"; break; case /* GG_DEBUG_FUNCTION */ 8: theme_format = "fdebug"; break; case /* GG_DEBUG_MISC */ 16: theme_format = "debug"; break; default: theme_format = "debug"; break; } tmp[strlen(tmp) - 1] = 0; buffer_add(BUFFER_DEBUG, NULL, tmp, DEBUG_MAX_LINES); if (ui_print) print_window("__debug", 0, theme_format, tmp); xfree(tmp); } #endif /* * ekg_ui_set() * * włącza interfejs o podanej nazwie. * * 0/-1 */ static int ekg_ui_set(const char *name) { if (!name) return 0; if (!strcasecmp(name, "none")) ui_init = ui_none_init; else if (!strcasecmp(name, "batch")) ui_init = ui_batch_init; #ifdef WITH_UI_READLINE else if (!strcasecmp(name, "readline")) ui_init = ui_readline_init; #endif #ifdef WITH_UI_NCURSES else if (!strcasecmp(name, "ncurses")) ui_init = ui_ncurses_init; #endif #ifdef WITH_UI_GTK else if (!strcasecmp(name, "gtk")) ui_init = ui_gtk_init; #endif else return -1; xfree(config_interface); config_interface = xstrdup(name); return 0; } int main(int argc, char **argv) { int auto_connect = 1, new_status = 0, ui_set = 0; int c = 0, set_private = 0, no_global_config = 0; char *tmp = NULL; char *load_theme = NULL, *new_reason = NULL, *new_profile = NULL; #ifdef WITH_IOCTLD const char *sock_path = NULL, *ioctld_path = IOCTLD_PATH; #endif struct sigaction sa; struct passwd *pw; struct gg_common si; struct option ekg_options[] = { { "back", optional_argument, 0, 'b' }, { "away", optional_argument, 0, 'a' }, { "ffc", optional_argument, 0, 'F' }, { "dnd", optional_argument, 0, 'd' }, { "invisible", optional_argument, 0, 'i' }, { "private", no_argument, 0, 'p' }, { "no-auto", no_argument, 0, 'n' }, { "control-pipe", required_argument, 0, 'c' }, { "frontend", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "ioctld-path", required_argument, 0, 'I' }, { "no-pipe", no_argument, 0, 'o' }, { "theme", required_argument, 0, 't' }, { "user", required_argument, 0, 'u' }, { "version", no_argument, 0, 'v' }, { "no-global-config", no_argument, 0, 'N' }, { "no-autorun", no_argument, 0, 'A' }, { 0, 0, 0, 0 } }; ekg_started = time(NULL); #ifdef HAVE_SETLOCALE if (getenv("LC_ALL") || getenv("LC_COLLATE")) { setlocale(LC_COLLATE, ""); strcoll_usable = 1; } #endif #ifdef WITH_UI_READLINE ui_init = ui_readline_init; #elif defined(WITH_UI_NCURSES) ui_init = ui_ncurses_init; #elif defined(WITH_UI_GTK) ui_init = ui_gtk_init; #else ui_init = ui_batch_init; #endif #ifdef WITH_FORCE_NCURSES ui_init = ui_ncurses_init; #endif ekg_ui_set(getenv("EKG_UI")); ekg_ui_set(getenv("EKG_FRONTEND")); srand(time(NULL)); strlcpy(argv0, argv[0], sizeof(argv0)); command_init(); if (!(home_dir = getenv("HOME"))) if ((pw = getpwuid(getuid()))) home_dir = pw->pw_dir; if (home_dir) home_dir = xstrdup(home_dir); if (!home_dir) { fprintf(stderr, "Nie mogę znaleźć katalogu domowego. Poproś administratora, żeby to naprawił.\n"); return 1; } memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGALRM, &sa, NULL); sa.sa_handler = handle_sigsegv; sigaction(SIGSEGV, &sa, NULL); sa.sa_handler = handle_sighup; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = handle_sigusr1; sigaction(SIGUSR1, &sa, NULL); sa.sa_handler = handle_sigusr2; sigaction(SIGUSR2, &sa, NULL); while ((c = getopt_long(argc, argv, "b::a::i::F::d::pnc:f:hI:ot:u:vNA", ekg_options, NULL)) != -1) { switch (c) { case 'b': if (!optarg && argv[optind] && argv[optind][0] != '-') optarg = argv[optind++]; new_status = (optarg) ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL; xfree(new_reason); new_reason = xstrdup(optarg); break; case 'a': if (!optarg && argv[optind] && argv[optind][0] != '-') optarg = argv[optind++]; new_status = (optarg) ? GG_STATUS_BUSY_DESCR : GG_STATUS_BUSY; xfree(new_reason); new_reason = xstrdup(optarg); break; case 'F': if (!optarg && argv[optind] && argv[optind][0] != '-') optarg = argv[optind++]; new_status = (optarg) ? GG_STATUS_FFC_DESCR : GG_STATUS_FFC; xfree(new_reason); new_reason = xstrdup(optarg); break; case 'd': if (!optarg && argv[optind] && argv[optind][0] != '-') optarg = argv[optind++]; new_status = (optarg) ? GG_STATUS_DND_DESCR : GG_STATUS_DND; xfree(new_reason); new_reason = xstrdup(optarg); break; case 'i': if (!optarg && argv[optind] && argv[optind][0] != '-') optarg = argv[optind++]; new_status = (optarg) ? GG_STATUS_INVISIBLE_DESCR : GG_STATUS_INVISIBLE; xfree(new_reason); new_reason = xstrdup(optarg); break; case 'p': set_private = 1; break; case 'n': auto_connect = 0; break; case 'N': no_global_config = 1; break; case 'h': printf("" "użycie: %s [OPCJE] [KOMENDY]\n" " -N, --no-global-config ignoruje globalny plik konfiguracyjny\n" " -A, --no-autorun nie uruchamia aliasu ,,autorun'' przy starcie\n" " -u, --user=NAZWA korzysta z profilu użytkownika o podanej nazwie\n" " -t, --theme=PLIK ładuje opis wyglądu z podanego pliku\n" " -c, --control-pipe=PLIK potok nazwany sterowania\n" " -o, --no-pipe wyłączenie potoku nazwanego sterowania\n" " -n, --no-auto nie łączy się automatycznie z serwerem\n" " -a, --away[=OPIS] domyślnie zmienia stan na ,,zajęty''\n" " -b, --back[=OPIS] domyślnie zmienia stan na ,,dostępny''\n" " -F, --ffc[=OPIS] domyślnie zmienia stan na ,,poGGadaj ze mną''\n" " -d, --dnd[=OPIS] domyślnie zmienia stan na ,,nie przeszkadzać''\n" " -i, --invisible[=OPIS] domyślnie zmienia stan na ,,niewidoczny''\n" " -p, --private domyślnie ustawia tryb ,,tylko dla znajomych''\n" " -v, --version wyświetla wersje programu i wychodzi\n" #ifdef WITH_IOCTLD " -I, --ioctld-path=ŚCIEŻKA ustawia ścieżkę do ioctld\n" #endif " -f, --frontend=NAZWA wybiera jeden z dostępnych interfejsów\n" " (none, batch" #ifdef WITH_UI_READLINE ", readline" #endif #ifdef WITH_UI_NCURSES ", ncurses" #endif #ifdef WITH_UI_GTK ", gtk" #endif ")\n" "\n", argv[0]); return 0; break; case 'u': new_profile = optarg; break; case 'c': pipe_file = optarg; break; case 'o': pipe_file = NULL; break; case 't': load_theme = optarg; break; case 'v': printf("ekg-%s\nlibgadu-%s (headers %s, protocol 0x%.2x, client \"%s\")\ncompile time: %s\n", VERSION, gg_libgadu_version(), GG_LIBGADU_VERSION, GG_DEFAULT_PROTOCOL_VERSION, GG_DEFAULT_CLIENT_VERSION, compile_time()); return 0; case 'A': no_autorun = 1; break; #ifdef WITH_IOCTLD case 'I': ioctld_path = optarg; break; #endif case 'f': ui_set = 1; if (ekg_ui_set(optarg)) { fprintf(stderr, "Nieznany interfejs %s.\n", optarg); return 1; } break; case '?': /* obsługiwane przez getopt */ fprintf(stdout, "Aby uzyskać więcej informacji, uruchom program z opcją --help.\n"); return 1; default: break; } } in_autoexec = 1; if (optind < argc) { batch_line = prepare_batch_line(argc, argv, optind); batch_mode = 1; if (!ui_set) ui_init = ui_batch_init; } if ((config_profile = new_profile)) tmp = saprintf("/%s", config_profile); else tmp = xstrdup(""); if (getenv("CONFIG_DIR")) config_dir = saprintf("%s/%s/gg%s", home_dir, getenv("CONFIG_DIR"), tmp); else config_dir = saprintf("%s/.gg%s", home_dir, tmp); xfree(tmp); tmp = NULL; if (!batch_mode && !ui_set && (tmp = config_read_variable("interface"))) { ekg_ui_set(tmp); xfree(tmp); } variable_init(); variable_set_default(); gg_debug_level = 0; if (getenv("EKG_DEBUG")) { if ((gg_debug_file = fopen(getenv("EKG_DEBUG"), "w"))) { setbuf(gg_debug_file, NULL); gg_debug_level = 255; } } #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) { #ifndef GG_DEBUG_DISABLE if (!gg_debug_file) gg_debug_handler = debug_handler; #endif gg_debug_level = 255; } #endif #ifdef WITH_UI_READLINE if (ui_init == ui_readline_init) { if (!gg_debug_file) gg_debug_handler = debug_handler; gg_debug_level = 255; } #endif #ifdef WITH_UI_GTK if (ui_init == ui_gtk_init) { #ifndef GG_DEBUG_DISABLE if (!gg_debug_file) gg_debug_handler = debug_handler; #endif gg_debug_level = 255; } #endif ekg_pid = getpid(); mesg_startup = mesg_set(MESG_CHECK); #ifdef WITH_PYTHON python_initialize(); #endif theme_init(); ui_screen_width = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80; ui_screen_height = getenv("LINES") ? atoi(getenv("LINES")) : 24; #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) { if ((tmp = config_read_variable("display_transparent"))) { config_display_transparent = atoi(tmp); xfree(tmp); } if ((tmp = config_read_variable("contacts"))) { config_contacts = atoi(tmp); xfree(tmp); } } #endif snprintf(sigsegv_msg, sizeof(sigsegv_msg), "\r\n" "\r\n" "*** Naruszenie ochrony pamięci ***\r\n" "\r\n" "Spróbuję zapisać ustawienia, ale nie obiecuję, że cokolwiek z tego\r\n" "wyjdzie. Trafią one do plików %s/config.%d\r\n" "oraz %s/userlist.%d\r\n" "\r\n" "Do pliku %s/debug.%d zapiszę ostatanie komunikaty\r\n" "z okna debugowania.\r\n" "\r\n" #ifdef HAVE_BACKTRACE "Jeśli zostanie utworzony plik %s/stack.%d, to uruchom\r\n" "polecenie:\r\n" "\r\n" " sed -e 's/^.*\\[//' -e 's/\\].*$//' %s/stack.%d | xargs addr2line -e %s\r\n" "\r\n" "i wyślij wynik jego działania na listę ekg-devel. Dzięki temu autorzy\r\n" "dowiedzą się, w którym miejscu wystąpił błąd i najprawdopodobniej pozwoli\r\n" "to uniknąć tego typu sytuacji w przyszłości.\r\n" "\r\n", config_dir, (int) getpid(), config_dir, (int) getpid(), config_dir, (int) getpid(), config_dir, (int) getpid(), config_dir, (int) getpid(), argv0); #else "Jeśli zostanie utworzony plik %s/core, spróbuj uruchomić\r\n" "polecenie:\r\n" "\r\n" " gdb %s %s/core\r\n" "\n" "zanotować kilka ostatnich linii, a następnie zanotować wynik polecenia\r\n" ",,bt''. Dzięki temu autorzy dowiedzą się, w którym miejscu wystąpił błąd\r\n" "i najprawdopodobniej pozwoli to uniknąć tego typu sytuacji w przyszłości.\r\n" "Jeśli core nie został utworzony a problem jest powtarzalny, spróbuj przed\r\n" "uruchomieniem ekg wydać polecenie ,,ulimit -c unlimited'' i powtórzyć błąd.\r\n" "Więcej szczegółów w dokumentacji, w pliku ,,gdb.txt''.\r\n" "\r\n", config_dir, (int) getpid(), config_dir, (int) getpid(), config_dir, (int) getpid(), config_dir, argv0, config_dir); #endif ui_init(); ui_event("theme_init"); if (ui_set && config_interface && strcmp(config_interface, "")) { char **arr = NULL; array_add(&arr, xstrdup("interface")); config_write_partly(arr); array_free(arr); } if (!no_global_config) config_read(SYSCONFDIR "/ekg.conf"); config_read(NULL); if (!no_global_config) config_read(SYSCONFDIR "/ekg-override.conf"); userlist_read(); update_status(); emoticon_read(); msg_queue_read(); in_autoexec = 0; ui_postinit(); ui_event("xterm_update"); #ifdef WITH_IOCTLD if (!batch_mode && config_ioctld_enable > 0) { sock_path = prepare_path(".socket", 1); if (!(ioctld_pid = fork())) { if (config_ioctld_enable == 1) execl(ioctld_path, "ioctld", sock_path, (void *) NULL); else if (config_ioctld_enable == 2) { char *portstr = saprintf("%d", config_ioctld_net_port); if (execl(ioctld_path, "ioctld", sock_path, portstr, (void*)NULL) == -1) xfree(portstr); } exit(0); } ioctld_socket(sock_path); atexit(ioctld_kill); } #endif /* WITH_IOCTLD */ if (!batch_mode && pipe_file) pipe_fd = init_control_pipe(pipe_file); if (!config_keep_reason) { xfree(config_reason); config_reason = NULL; config_status = ekg_hide_descr_status(config_status); } /* określanie stanu klienta po włączeniu */ if (new_status) { if (config_keep_reason && config_reason) { switch (new_status) { case GG_STATUS_AVAIL: new_status = GG_STATUS_AVAIL_DESCR; break; case GG_STATUS_BUSY: new_status = GG_STATUS_BUSY_DESCR; break; case GG_STATUS_INVISIBLE: new_status = GG_STATUS_INVISIBLE_DESCR; break; } } config_status = new_status | (GG_S_F(config_status) ? GG_STATUS_FRIENDS_MASK : 0); } if (new_reason) { xfree(config_reason); config_reason = new_reason; } if (set_private) config_status |= GG_STATUS_FRIENDS_MASK; /* jeśli ma być theme, niech będzie theme */ if (load_theme) theme_read(load_theme, 1); else if (config_theme) theme_read(config_theme, 1); theme_cache_reset(); time(&last_action); /* dodajemy stdin do oglądanych deskryptorów */ if (!batch_mode && ui_init != ui_none_init) { memset(&si, 0, sizeof(si)); si.fd = 0; si.check = GG_CHECK_READ; si.state = GG_STATE_READING_DATA; si.type = GG_SESSION_USER0; si.id = 0; si.timeout = -1; list_add(&watches, &si, sizeof(si)); } /* stderr */ if (!batch_mode) { struct gg_exec se; int fd[2]; if (!pipe(fd)) { memset(&se, 0, sizeof(se)); se.fd = fd[0]; se.check = GG_CHECK_READ; se.state = GG_STATE_READING_DATA; se.type = GG_SESSION_USER3; se.id = 2; se.timeout = -1; se.buf = string_init(NULL); list_add(&watches, &se, sizeof(se)); fcntl(fd[0], F_SETFL, O_NONBLOCK); fcntl(fd[1], F_SETFL, O_NONBLOCK); old_stderr = fcntl(2, F_DUPFD, 0); dup2(fd[1], 2); } } /* dodajemy otwarty potok sterujacy do oglądanych deskryptorów */ if (!batch_mode && pipe_fd > 0) { memset(&si, 0, sizeof(si)); si.fd = pipe_fd; si.check = GG_CHECK_READ; si.state = GG_STATE_READING_DATA; si.type = GG_SESSION_USER1; si.id = 0; si.timeout = -1; list_add(&watches, &si, sizeof(si)); } if (!batch_mode && config_display_welcome) print("welcome", VERSION); if (!config_uin || !config_password) print("no_config"); ui_event("config_changed"); if (!config_log_path) config_log_path = xstrdup(prepare_path("history", 0)); #ifdef HAVE_OPENSSL sim_key_path = xstrdup(prepare_path("keys/", 0)); #endif changed_dcc("dcc"); changed_dcc("dcc_ip"); #ifdef WITH_PYTHON python_autorun(); #endif if (!no_autorun) { list_t l; for (l = aliases; l; l = l->next) { struct alias *a = l->data; if (!strcasecmp("autorun", a->name)) { command_exec(NULL, "/autorun", 0); break; } } } if (config_uin && config_password && auto_connect) { print("connecting"); connecting = 1; ekg_connect(); } if (config_auto_save) last_save = time(NULL); ui_loop(); ekg_exit(); return 0; } /* * ekg_exit() * * wychodzi z klienta sprzątając przy okazji wszystkie sesje, zwalniając * pamięć i czyszcząc pokój. */ void ekg_exit() { char **vars = NULL; list_t l; int i; #ifdef WITH_PYTHON /* * udawaj, że nie wychodzimy, bo inaczej ewentualny command_exec() * będzię nas wywoływał rekurencyjnie. */ quit_command = 0; python_finalize(); quit_command = 1; #endif ekg_logoff(sess, NULL); list_remove(&watches, sess, 0); gg_free_session(sess); sess = NULL; ui_deinit(); msg_queue_write(); xfree(last_search_first_name); xfree(last_search_last_name); xfree(last_search_nickname); if (config_last_sysmsg_changed) array_add(&vars, xstrdup("last_sysmsg")); if (config_keep_reason) { if (config_keep_reason != 2) array_add(&vars, xstrdup("status")); array_add(&vars, xstrdup("reason")); } if (config_server_save) array_add(&vars, xstrdup("server")); if (config_windows_save) array_add(&vars, xstrdup("windows_layout")); if (vars) { config_write_partly(vars); array_free(vars); } if (config_changed && !config_speech_app && config_save_question) { char line[80]; printf("%s", format_find("config_changed")); fflush(stdout); if (fgets(line, sizeof(line), stdin)) { if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = 0; if (!strcasecmp(line, "tak") || !strcasecmp(line, "yes") || !strcasecmp(line, "t") || !strcasecmp(line, "y")) { if (userlist_write(0) || config_write(NULL)) printf("Wystąpił błąd podczas zapisu.\n"); } } else printf("\n"); } for (i = 0; i < SEND_NICKS_MAX; i++) { xfree(send_nicks[i]); send_nicks[i] = NULL; } send_nicks_count = 0; for (l = searches; l; l = l->next) gg_pubdir50_free(l->data); for (l = children; l; l = l->next) { struct process *p = l->data; kill(p->pid, SIGTERM); } if (pipe_fd > 0) close(pipe_fd); if (pipe_file) unlink(pipe_file); #ifdef HAVE_OPENSSL xfree(sim_key_path); #endif for (l = watches; l; l = l->next) { struct gg_session *s = l->data; int i; for (i = 0; handlers[i].reaper; i++) { if (handlers[i].type == s->type) { handlers[i].reaper(s); break; } } } list_destroy(watches, 0); msg_queue_free(); alias_free(); conference_free(); userlist_free(); theme_free(); variable_free(); event_free(); emoticon_free(); sms_away_free(); check_mail_free(); command_free(); timer_free(); binding_free(); last_free(); buffer_free(); list_destroy(autofinds, 1); list_destroy(spiedlist, 1); xfree(home_dir); xfree(last_tokenid); xfree(gg_proxy_host); xfree(gg_proxy_username); xfree(gg_proxy_password); xfree(config_dir); /* kapitan schodzi ostatni */ if (gg_debug_file) { fclose(gg_debug_file); gg_debug_file = NULL; } mesg_set(mesg_startup); exit(0); } ekg-1.9~pre+r2855/src/emoticons.c000066400000000000000000000101471174410337000165550ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include "dynstuff.h" #include "emoticons.h" #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "userlist.h" #include "xmalloc.h" list_t emoticons = NULL; int config_emoticons = 1; /* * emoticon_add() * * dodaje dany emoticon do listy. * * - name - nazwa, * - value - wartość. * * 0/-1 */ int emoticon_add(const char *name, const char *value) { struct emoticon e; list_t l; if (!name || !value) return -1; for (l = emoticons; l; l = l->next) { struct emoticon *g = l->data; if (!strcasecmp(name, g->name)) { xfree(g->value); g->value = xstrdup(value); return 0; } } e.name = xstrdup(name); e.value = xstrdup(value); return (list_add(&emoticons, &e, sizeof(e)) ? 0 : -1); } /* * emoticon_remove() * * usuwa emoticon o danej nazwie. * * - name. * * 0/-1 */ int emoticon_remove(const char *name) { list_t l; for (l = emoticons; l; l = l->next) { struct emoticon *f = l->data; if (!strcasecmp(f->name, name)) { xfree(f->value); xfree(f->name); list_remove(&emoticons, f, 1); return 0; } } return -1; } /* * emoticon_read() * * ładuje do listy wszystkie makra z pliku ~/.gg/emoticons * format tego pliku w dokumentacji. * * 0/-1 */ int emoticon_read() { const char *filename; char *buf, **emot; FILE *f; if (!(filename = prepare_path("emoticons", 0))) return -1; if (!(f = fopen(filename, "r"))) return -1; while ((buf = read_file(f))) { if (buf[0] == '#') { xfree(buf); continue; } emot = array_make(buf, "\t", 2, 1, 1); if (array_count(emot) == 2) emoticon_add(emot[0], emot[1]); array_free(emot); xfree(buf); } fclose(f); return 0; } /* * emoticon_expand() * * rozwija definicje makr (najczęściej będą to emoticony) * * - s - string z makrami. * * zwraca zaalokowany, rozwinięty string. */ char *emoticon_expand(const char *s) { list_t l = NULL; const char *ss; char *ms; size_t n = 0; for (ss = s; *ss; ss++) { struct emoticon *e = NULL; size_t ns = strlen(ss); int ret = 1; for (l = emoticons; l && ret; l = (ret ? l->next : l)) { size_t nn; e = l->data; nn = strlen(e->name); if (ns >= nn) ret = strncmp(ss, e->name, nn); } if (l) { e = l->data; n += strlen(e->value); ss += strlen(e->name) - 1; } else n++; } ms = xcalloc(1, n + 1); for (ss = s; *ss; ss++) { struct emoticon *e = NULL; size_t ns = strlen(ss); int ret = 1; for (l = emoticons; l && ret; l = (ret ? l->next : l)) { size_t n; e = l->data; n = strlen(e->name); if (ns >= n) ret = strncmp(ss, e->name, n); } if (l) { e = l->data; strlcat(ms, e->value, n + 1); ss += strlen(e->name) - 1; } else ms[strlen(ms)] = *ss; } return ms; } /* * emoticon_free() * * usuwa pamięć zajętą przez emoticony. */ void emoticon_free() { list_t l; if (!emoticons) return; for (l = emoticons; l; l = l->next) { struct emoticon *e = l->data; xfree(e->name); xfree(e->value); } list_destroy(emoticons, 1); emoticons = NULL; } ekg-1.9~pre+r2855/src/emoticons.h000066400000000000000000000024411174410337000165600ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __EMOTICONS_H #define __EMOTICONS_H struct emoticon { char *name; char *value; }; list_t emoticons; int emoticon_read(void); char *emoticon_expand(const char *s); void emoticon_free(void); int emoticon_add(const char *name, const char *value); int emoticon_remove(const char *name); #endif /* __EMOTICONS_H */ ekg-1.9~pre+r2855/src/events.c000066400000000000000000002336141174410337000160670ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2006 Wojtek Kaniewski * Piotr Wysocki * Dawid Jarosz * Piotr Domagalski * Adam Czerwiński * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "commands.h" #include "emoticons.h" #include "events.h" #include "libgadu.h" #include "log.h" #include "msgqueue.h" #ifdef HAVE_OPENSSL # include "simlite.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "userlist.h" #include "configfile.h" #include "voice.h" #include "xmalloc.h" #include "token.h" #ifdef WITH_PYTHON # include "python.h" #endif #ifdef HAVE_JPEGLIB_H # include #endif #ifdef HAVE_GIF_LIB_H # include /* open() */ # include #endif void handle_msg(), handle_ack(), handle_status(), handle_notify(), handle_success(), handle_failure(), handle_search50(), handle_change50(), handle_status60(), handle_notify60(), handle_userlist(), handle_image_request(), handle_image_reply(), handle_dcc7_new(), handle_dcc7_accept(), handle_dcc7_reject(); static int hide_notavail = 0; /* czy ma ukrywać niedostępnych -- tylko zaraz po połączeniu */ static int dcc_limit_time = 0; /* czas pierwszego liczonego połączenia */ static int dcc_limit_count = 0; /* ilość połączeń od ostatniego razu */ static int auto_find_limit = 100; /* ilość osób, których nie znamy, a szukaliśmy po odebraniu msg */ static struct handler handlers[] = { { GG_EVENT_MSG, handle_msg }, { GG_EVENT_ACK, handle_ack }, { GG_EVENT_STATUS, handle_status }, { GG_EVENT_NOTIFY, handle_notify }, { GG_EVENT_STATUS60, handle_status60 }, { GG_EVENT_NOTIFY60, handle_notify60 }, { GG_EVENT_NOTIFY_DESCR, handle_notify }, { GG_EVENT_CONN_SUCCESS, handle_success }, { GG_EVENT_CONN_FAILED, handle_failure }, { GG_EVENT_DISCONNECT, handle_disconnect }, { GG_EVENT_PUBDIR50_SEARCH_REPLY, handle_search50 }, { GG_EVENT_PUBDIR50_WRITE, handle_change50 }, { GG_EVENT_USERLIST, handle_userlist }, { GG_EVENT_IMAGE_REQUEST, handle_image_request }, { GG_EVENT_IMAGE_REPLY, handle_image_reply }, { GG_EVENT_DCC7_NEW, handle_dcc7_new }, { GG_EVENT_DCC7_ACCEPT, handle_dcc7_accept }, { GG_EVENT_DCC7_REJECT, handle_dcc7_reject }, { 0, NULL } }; /* * print_message() * * funkcja ładnie formatuje treść wiadomości, zawija linijki, wyświetla * kolorowe ramki i takie tam. * * - e - zdarzenie wiadomości * - u - wpis użytkownika w userliście * - chat - rodzaj wiadomości (0 - msg, 1 - chat, 2 - sysmsg) * - secure - czy wiadomość jest bezpieczna * * nie zwraca niczego. efekt widać na ekranie. */ void print_message(struct gg_event *e, struct userlist *u, int chat, int secure) { int width, next_width, i, j, mem_width = 0; time_t tt, t = e->event.msg.time; int separate = (e->event.msg.sender != config_uin || chat == 3); int timestamp_type = 0; char *mesg, *buf, *line, *next, *format = NULL, *format_first = ""; char *next_format = NULL, *head = NULL, *foot = NULL; char *timestamp = NULL, *save, *secure_label = NULL; char *line_width = NULL, timestr[100], *target, *cname; char *formatmap = NULL; struct tm *tm; int now_days; struct conference *c = NULL; if ((config_make_window & 4) && (chat == 0)) separate = 0; /* tworzymy mapę formatowanego tekstu. dla każdego znaku wiadomości * zapisujemy jeden znak koloru z docs/themes.txt lub \0 jeśli nie * trzeba niczego zmieniać. */ if (e->event.msg.formats && e->event.msg.formats_length) { unsigned char *p = e->event.msg.formats; char last_attr = 0, *attrmap; if (config_display_color_map && strlen(config_display_color_map) == 8) attrmap = config_display_color_map; else attrmap = "nTgGbBrR"; formatmap = xcalloc(1, strlen(e->event.msg.message)); for (i = 0; i < e->event.msg.formats_length; ) { int pos = p[i] + p[i + 1] * 256; if (pos >= strlen(e->event.msg.message)) { xfree(formatmap); formatmap = NULL; break; } if ((p[i + 2] & GG_FONT_COLOR)) { formatmap[pos] = color_map(p[i + 3], p[i + 4], p[i + 5]); if (formatmap[pos] == 'k') formatmap[pos] = 'n'; } if ((p[i + 2] & 7) || !p[i + 2] || !(p[i + 2] && GG_FONT_COLOR) || ((p[i + 2] & GG_FONT_COLOR) && !p[i + 3] && !p[i + 4] && !p[i + 5])) formatmap[pos] = attrmap[p[i + 2] & 7]; i += (p[i + 2] & GG_FONT_COLOR) ? 6 : 3; } /* teraz powtarzamy formaty tam, gdzie jest przejście do * nowej linii i odstępy. dzięki temu oszczędzamy sobie * mieszania niżej w kodzie. */ for (i = 0; formatmap && i < strlen(e->event.msg.message); i++) { if (formatmap[i]) last_attr = formatmap[i]; if (i > 0 && strchr(" \n", e->event.msg.message[i - 1])) formatmap[i] = last_attr; } } if (secure) secure_label = format_string(format_find("secure")); if (e->event.msg.recipients) { c = conference_find_by_uins(e->event.msg.sender, e->event.msg.recipients, e->event.msg.recipients_count, 0); if (!c) { string_t tmp = string_init(NULL); int first = 0, i; for (i = 0; i < e->event.msg.recipients_count; i++) { if (first++) string_append_c(tmp, ','); string_append(tmp, itoa(e->event.msg.recipients[i])); } string_append_c(tmp, ' '); string_append(tmp, itoa(e->event.msg.sender)); c = conference_create(tmp->str); string_free(tmp, 1); } if (c) target = xstrdup(c->name); else target = xstrdup((chat == 2) ? "__status" : ((u && u->display) ? u->display : itoa(e->event.msg.sender))); } else target = xstrdup((chat == 2) ? "__status" : ((u && u->display) ? u->display : itoa(e->event.msg.sender))); cname = (c ? c->name : ""); tt = time(NULL); tm = localtime(&tt); now_days = tm->tm_yday; tm = localtime(&e->event.msg.time); if (t - config_time_deviation <= tt && tt <= t + config_time_deviation) timestamp_type = 2; else if (now_days == tm->tm_yday) timestamp_type = 1; switch (chat) { case 0: format = "message_line"; format_first = (c) ? "message_conference_line_first" : "message_line_first"; line_width = "message_line_width"; head = (c) ? "message_conference_header" : "message_header"; foot = "message_footer"; if (timestamp_type == 1) timestamp = "message_timestamp_today"; else if (timestamp_type == 2) timestamp = "message_timestamp_now"; else timestamp = "message_timestamp"; break; case 1: format = "chat_line"; format_first = (c) ? "chat_conference_line_first" : "chat_line_first"; line_width = "chat_line_width"; head = (c) ? "chat_conference_header" : "chat_header"; foot = "chat_footer"; if (timestamp_type == 1) timestamp = "chat_timestamp_today"; else if (timestamp_type == 2) timestamp = "chat_timestamp_now"; else timestamp = "chat_timestamp"; break; case 2: format = "sysmsg_line"; line_width = "sysmsg_line_width"; head = "sysmsg_header"; foot = "sysmsg_footer"; break; case 3: case 4: format = "sent_line"; format_first = (c) ? "sent_conference_line_first" : "sent_line_first"; line_width = "sent_line_width"; head = (c) ? "sent_conference_header" : "sent_header"; foot = "sent_footer"; if (timestamp_type == 1) timestamp = "sent_timestamp_today"; else if (timestamp_type == 2) timestamp = "sent_timestamp_now"; else timestamp = "sent_timestamp"; break; } /* jeżeli chcemy, dodajemy do bufora ,,last'' wiadomość... */ if (config_last & 3 && (chat >= 0 && chat <= 2)) last_add(0, e->event.msg.sender, tt, e->event.msg.time, e->event.msg.message); strftime(timestr, sizeof(timestr), format_find(timestamp), tm); if (!(width = atoi(format_find(line_width)))) width = ui_screen_width - 2; if (width < 0) { width = ui_screen_width + width; if (config_timestamp) width -= strlen(config_timestamp) - 6; } next_width = width; if (!strcmp(format_find(format_first), "")) { print_window(target, separate, head, format_user(e->event.msg.sender), timestr, cname, (secure) ? secure_label : ""); next_format = format; mem_width = width + 1; } else { char *tmp, *p; next_format = format; format = format_first; /* zmniejsz długość pierwszej linii o długość prefiksu z rozmówcą, timestampem itd. */ tmp = format_string(format_find(format), "", format_user(e->event.msg.sender), timestr, cname, (secure) ? secure_label : ""); mem_width = width + strlen(tmp); for (p = tmp; *p && *p != '\n'; p++) { if (*p == 27) { /* pomiń kolorki */ while (*p && *p != 'm') p++; } else width--; } xfree(tmp); tmp = format_string(format_find(next_format), "", "", "", ""); next_width -= strlen(tmp); xfree(tmp); } buf = xmalloc(mem_width); mesg = save = (strlen(e->event.msg.message) > 0) ? xstrdup(e->event.msg.message) : xstrdup(" "); for (i = 0; i < strlen(mesg); i++) /* XXX ładniejsze taby */ if (mesg[i] == '\t') mesg[i] = ' '; while ((line = get_line(&mesg))) { const char *last_format_ansi = ""; int buf_offset; #ifdef WITH_WAP if (config_wap_enabled && e->event.msg.sender != config_uin) { FILE *wap; char waptime[25], waptime2[10]; const char *waplog; struct tm *waptm; waptm = localtime(&tt); if (config_wap_enabled == 2) { strftime(waptime2, sizeof(waptime2), "%H:%M%S", waptm); snprintf(waptime, sizeof(waptime), "wap%7s_%d", waptime2, e->event.msg.sender); if ((waplog = prepare_path(waptime, 1)) && (wap = fopen(waplog, "a"))) { fprintf(wap, "%s;%s\n", target, line); fclose(wap); } } else { strftime(waptime2, sizeof(waptime2), "%H:%M", waptm); sprintf(waptime, "wap%5s", waptime2); if ((waplog = prepare_path(waptime, 1)) && (wap = fopen(waplog, "a"))) { fprintf(wap,"%s(%s):%s\n", target, waptime2, line); fclose(wap); } } } #endif for (; strlen(line); line = next) { char *emotted = NULL, *formatted; if (strlen(line) <= width) { strlcpy(buf, line, mem_width); next = line + strlen(line); } else { int len = width; for (j = width; j; j--) if (line[j] == ' ') { len = j; break; } strlcpy(buf, line, len + 1); buf[len] = 0; next = line + len; while (*next == ' ') next++; } buf_offset = (int) (line - save); if (formatmap) { string_t s = string_init(""); int i; string_append(s, last_format_ansi); for (i = 0; i < strlen(buf); i++) { if (formatmap[buf_offset + i]) { last_format_ansi = format_ansi(formatmap[buf_offset + i]); string_append(s, last_format_ansi); } string_append_c(s, buf[i]); } formatted = string_free(s, 0); } else formatted = xstrdup(buf); if (config_emoticons) emotted = emoticon_expand(formatted); print_window(target, separate, format, (emotted) ? emotted : formatted, format_user(e->event.msg.sender), timestr, cname, (secure) ? secure_label : ""); width = next_width; format = next_format; xfree(emotted); xfree(formatted); } } xfree(buf); xfree(save); xfree(secure_label); xfree(formatmap); if (!strcmp(format_find(format_first), "")) print_window(target, separate, foot); xfree(target); } /* * handle_msg() * * funkcja obsługuje przychodzące wiadomości. * * - e - opis zdarzenia. * * nie zwraca niczego. */ void handle_msg(struct gg_event *e) { struct userlist *u = userlist_find(e->event.msg.sender, NULL); int chat = ((e->event.msg.msgclass & 0x0f) == GG_CLASS_CHAT), secure = 0, hide = 0; list_t image, images = NULL; if (!e->event.msg.message) return; if ((e->event.msg.msgclass & GG_CLASS_CTCP)) { list_t l; int dccs = 0; gg_debug(GG_DEBUG_MISC, "// ekg: received ctcp\n"); for (l = watches; l; l = l->next) { struct gg_dcc *d = l->data; if (d->type == GG_SESSION_DCC) dccs++; } if (dccs > 50) { char *tmp = saprintf("/ignore %d", e->event.msg.sender); print_status("dcc_attack", format_user(e->event.msg.sender)); command_exec(NULL, tmp, 0); xfree(tmp); return; } if (config_dcc && u) { struct gg_dcc *d; if (!(d = gg_dcc_get_file(u->ip.s_addr, u->port, config_uin, e->event.msg.sender))) { print_status("dcc_error", strerror(errno)); return; } list_add(&watches, d, 0); } return; } if (e->event.msg.formats_length > 0) { unsigned char *p = e->event.msg.formats; int i, imageno = 0; gg_debug(GG_DEBUG_MISC, "// ekg: received formatting info (len=%d):", e->event.msg.formats_length); for (i = 0; i < e->event.msg.formats_length; i++) gg_debug(GG_DEBUG_MISC, " %.2x", p[i]); gg_debug(GG_DEBUG_MISC, "\n"); for (i = 0; i < e->event.msg.formats_length; ) { unsigned char font = p[i + 2]; i += 3; if ((font & GG_FONT_IMAGE)) { struct gg_msg_richtext_image *m = (void*) &p[i]; gg_debug(GG_DEBUG_MISC, "// ekg: inline image: sender=%d, size=%d, crc32=%.8x\n", e->event.msg.sender, gg_fix32(m->size), gg_fix32(m->crc32)); if (config_receive_images) list_add(&images, m, sizeof(*m)); imageno++; i += sizeof(*m); } if ((font & GG_FONT_COLOR)) i += 3; } /* ignorujemy wiadomości bez treści zawierające jedynie obrazek(ki) */ if (config_ignore_empty_msg && imageno && strlen(e->event.msg.message) == 0) { list_destroy(images, 1); return; } } #ifdef HAVE_OPENSSL if (config_encryption == 1 || config_encryption == 2) { char *msg = sim_message_decrypt(e->event.msg.message, e->event.msg.sender); if (msg) { strlcpy(e->event.msg.message, msg, strlen(e->event.msg.message) + 1); xfree(msg); secure = 1; } else gg_debug(GG_DEBUG_MISC, "// ekg: simlite decryption failed: %s\n", sim_strerror(sim_errno)); } #endif cp_to_iso(e->event.msg.message); #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(msg, "(isisii)", e->event.msg.sender, ((u && u->display) ? u->display : ""), e->event.msg.msgclass, e->event.msg.message, e->event.msg.time, secure) { char *b, *d; int f; PYTHON_HANDLE_RESULT("isisii", &e->event.msg.sender, &b, &e->event.msg.msgclass, &d, &e->event.msg.time, &f) { xfree(e->event.msg.message); e->event.msg.message = xstrdup(d); } } PYTHON_HANDLE_FOOTER() switch (python_handle_result) { case 0: list_destroy(images, 1); return; case 2: hide = 1; } #endif if (e->event.msg.sender == 0) { if (e->event.msg.msgclass > config_last_sysmsg) { if (!hide) print_message(e, u, 2, 0); if (config_beep) ui_beep(); play_sound(config_sound_sysmsg_file); config_last_sysmsg = e->event.msg.msgclass; config_last_sysmsg_changed = 1; } list_destroy(images, 1); return; } if (e->event.msg.recipients_count) { struct conference *c = conference_find_by_uins( e->event.msg.sender, e->event.msg.recipients, e->event.msg.recipients_count, 0); if (c && c->ignore) { list_destroy(images, 1); return; } } if ((!u && config_ignore_unknown_sender) || ignored_check(e->event.msg.sender) & IGNORE_MSG) { if (config_log_ignored) put_log(e->event.msg.sender, "%sign,%ld,%s,%s,%s,%s\n", (chat) ? "chatrecv" : "msgrecv", e->event.msg.sender, ((u && u->display) ? u->display : ""), log_timestamp(time(NULL)), log_timestamp(e->event.msg.time), e->event.msg.message); list_destroy(images, 1); return; } for (image = images; image; image = image->next) { struct gg_msg_richtext_image *i = image->data; gg_debug(GG_DEBUG_MISC, "// ekg: requesting image size=%d crc32=%.8x from %d\n", gg_fix32(i->size), gg_fix32(i->crc32), e->event.msg.sender); gg_image_request(sess, e->event.msg.sender, i->size, i->crc32); } list_destroy(images, 1); #ifdef HAVE_OPENSSL if (config_encryption && !strncmp(e->event.msg.message, "-----BEGIN RSA PUBLIC KEY-----", 20)) { char *name; const char *target = ((u && u->display) ? u->display : itoa(e->event.msg.sender)); FILE *f; print_window(target, 0, "key_public_received", format_user(e->event.msg.sender)); if (mkdir(prepare_path("keys", 1), 0700) && errno != EEXIST) { print_window(target, 0, "key_public_write_failed", strerror(errno)); return; } name = saprintf("%s/%d.pem", prepare_path("keys", 0), e->event.msg.sender); if (!(f = fopen(name, "w"))) { print_window(target, 0, "key_public_write_failed", strerror(errno)); xfree(name); return; } fprintf(f, "%s", e->event.msg.message); fclose(f); xfree(name); return; } #endif if (u && u->display) add_send_nick(u->display); else add_send_nick(itoa(e->event.msg.sender)); if (!hide) { print_message(e, u, chat, secure); if (config_beep && ((chat) ? config_beep_chat : config_beep_msg)) ui_beep(); play_sound((chat) ? config_sound_chat_file : config_sound_msg_file); } put_log(e->event.msg.sender, "%s,%ld,%s,%s,%s,%s\n", (chat) ? "chatrecv" : "msgrecv", e->event.msg.sender, ((u && u->display) ? u->display : ""), log_timestamp(time(NULL)), log_timestamp(e->event.msg.time), e->event.msg.message); if (!(ignored_check(e->event.msg.sender) & IGNORE_EVENTS)) event_check((chat) ? EVENT_CHAT : EVENT_MSG, e->event.msg.sender, e->event.msg.message); if (config_sms_away && (GG_S_B(config_status) || (GG_S_I(config_status) && config_sms_away & 4)) && config_sms_app && config_sms_number) { if (!(ignored_check(e->event.msg.sender) & IGNORE_SMSAWAY)) { char *foo, sender[100]; sms_away_add(e->event.msg.sender); if (sms_away_check(e->event.msg.sender)) { if (u && u->display) snprintf(sender, sizeof(sender), "%s/%u", u->display, u->uin); else snprintf(sender, sizeof(sender), "%u", e->event.msg.sender); if (config_sms_max_length && strlen(e->event.msg.message) > config_sms_max_length) e->event.msg.message[config_sms_max_length] = 0; if (e->event.msg.recipients_count) foo = format_string(format_find("sms_conf"), sender, e->event.msg.message); else foo = format_string(format_find((chat) ? "sms_chat" : "sms_msg"), sender, e->event.msg.message); /* niech nie wysyła smsów, jeśli brakuje formatów */ if (strcmp(foo, "")) send_sms(config_sms_number, foo, 0); xfree(foo); } } } if (!u && config_auto_find) { list_t l; int do_find = 1, i; for (l = autofinds, i = 0; l; l = l->next, i++) { uin_t *d = l->data; if (*d == e->event.msg.sender) { do_find = 0; break; } } if (do_find) { char *tmp; if (i == auto_find_limit) { gg_debug(GG_DEBUG_MISC, "// autofind reached %d limit, removing the oldest uin: %d\n", auto_find_limit, *((uin_t *)autofinds->data)); list_remove(&autofinds, autofinds->data, 1); } list_add(&autofinds, &e->event.msg.sender, sizeof(uin_t)); tmp = saprintf("/find -u %d", e->event.msg.sender); command_exec(itoa(e->event.msg.sender), tmp, 0); xfree(tmp); } } } /* * handle_ack() * * funkcja obsługuje potwierdzenia wiadomości. * * - e - opis zdarzenia. * * nie zwraca niczego. */ void handle_ack(struct gg_event *e) { struct userlist *u = userlist_find(e->event.ack.recipient, NULL); const char *tmp, *target = ((u && u->display) ? u->display : itoa(e->event.ack.recipient)); static int show_short_ack_filtered = 0; if (!e->event.ack.seq) /* ignorujemy potwierdzenia ctcp */ return; msg_queue_remove(e->event.ack.seq); if (!(ignored_check(e->event.ack.recipient) & IGNORE_EVENTS)) { int event; if (e->event.ack.status == GG_ACK_BLOCKED) event = EVENT_FILTERED; else if (e->event.ack.status == GG_ACK_DELIVERED) event = EVENT_DELIVERED; else if (e->event.ack.status == GG_ACK_QUEUED) event = EVENT_QUEUED; else if (e->event.ack.status == GG_ACK_MBOXFULL) event = EVENT_MBOXFULL; else event = EVENT_NOT_DELIVERED; event_check(event, e->event.ack.recipient, NULL); } if (u && (e->event.ack.status == GG_ACK_DELIVERED) && GG_S_NA(u->status) && !(ignored_check(u->uin) & IGNORE_STATUS)) e->event.ack.status = GG_ACK_BLOCKED; if (!config_display_ack) return; /* xxx: dopisać EVENT_MBOXFULL i EVENT_NOT_DELIVERED do config_display_ack */ if (config_display_ack == 2 && e->event.ack.status == GG_ACK_QUEUED) return; if (config_display_ack == 3 && e->event.ack.status == GG_ACK_DELIVERED) return; if (e->event.ack.status == GG_ACK_BLOCKED) { if (show_short_ack_filtered) tmp = "ack_filtered_short"; else { tmp = "ack_filtered"; show_short_ack_filtered = 1; } } else if (e->event.ack.status == GG_ACK_DELIVERED) tmp = "ack_delivered"; else if (e->event.ack.status == GG_ACK_QUEUED) tmp = "ack_queued"; else if (e->event.ack.status == GG_ACK_MBOXFULL) tmp = "ack_mboxfull"; else tmp = "ack_not_delivered"; print_window(target, 0, tmp, format_user(e->event.ack.recipient)); } /* * handle_common() * * ujednolicona obsługa zmiany w userliście dla handle_status() * i handle_notify(). utrzymywanie tego samego kodu w kilku miejscach * jest kompletnie bez sensu. * * - uin - numer delikwenta, * - status - nowy stan, * - idescr - nowy opis, * - itime - nowy czas powrotu, * - ip - nowy adres IP, * - port - nowy port, * - version - nowa wersja, * - image_size - nowy rozmiar obrazka. */ void handle_common(uin_t uin, int status, const char *idescr, int dtime, uint32_t ip, uint16_t port, int version, int image_size) { struct userlist *u; static struct userlist ucache[20]; static time_t seencache[20]; struct status_table { int status; int event; char *log; char *format; }; struct status_table st[] = { { GG_STATUS_AVAIL, EVENT_AVAIL, "avail", "status_avail" }, { GG_STATUS_AVAIL_DESCR, EVENT_AVAIL, "avail", "status_avail_descr" }, { GG_STATUS_BUSY, EVENT_AWAY, "busy", "status_busy" }, { GG_STATUS_BUSY_DESCR, EVENT_AWAY, "busy", "status_busy_descr" }, { GG_STATUS_DND, EVENT_DND, "dnd", "status_dnd" }, { GG_STATUS_DND_DESCR, EVENT_DND, "dnd", "status_dnd_descr" }, { GG_STATUS_FFC, EVENT_FFC, "ffc", "status_ffc" }, { GG_STATUS_FFC_DESCR, EVENT_FFC, "ffc", "status_ffc_descr" }, { GG_STATUS_INVISIBLE, EVENT_INVISIBLE, "invisible", "status_invisible" }, { GG_STATUS_INVISIBLE_DESCR, EVENT_INVISIBLE, "invisible", "status_invisible_descr" }, { GG_STATUS_NOT_AVAIL, EVENT_NOT_AVAIL, "notavail", "status_not_avail" }, { GG_STATUS_NOT_AVAIL_DESCR, EVENT_NOT_AVAIL, "notavail", "status_not_avail_descr" }, { 0, 0, NULL, NULL } }; struct status_table *s; int prev_status, hide = 0; int have_unknown = 0; int ignore_status, ignore_status_descr, ignore_events, ignore_notify; unsigned char *descr = NULL; #ifdef WITH_PYTHON list_t l; #endif /* w gg 8.0 status ma czasami maske 0x4000, usuwamy */ status = GG_S(status); /* nie pokazujemy nieznajomych, chyba ze display_notify & 4 */ if (!(u = userlist_find(uin, NULL))) { if (!(config_display_notify & 4)) return; else { int i; time_t cur = time(NULL); have_unknown = 1; /* najpierw przeszukanie cache numerków. */ for (i = 0; i < sizeof(ucache) / sizeof(ucache[0]); i++) { if (ucache[i].uin == uin) { u = &ucache[i]; seencache[i] = cur; break; } } /* jeśli nie znaleźliśmy w cache, to wybieramy najdawniej * widziany element cache i zastępujemy go nowym. jeśli * któreś pole w cache jest wolne, to jest przypisywane * aktualnemu numerkowi (bo wtedy oldest == 0 i nic nie * będzie od niego mniejsze). */ if (!u) { time_t oldest = time(NULL), *sptr = (time_t *) NULL; for (i = 0; i < sizeof(ucache) / sizeof(ucache[0]); i++) { if (seencache[i] < oldest) { sptr = &seencache[i]; oldest = *sptr; u = &ucache[i]; } } memset(u, 0, sizeof(struct userlist)); u->uin = uin; u->status = GG_STATUS_NOT_AVAIL; *sptr = time(NULL); } } } ignore_status = ignored_check(uin) & IGNORE_STATUS; ignore_status_descr = ignored_check(uin) & IGNORE_STATUS_DESCR; ignore_events = ignored_check(uin) & IGNORE_EVENTS; ignore_notify = ignored_check(uin) & IGNORE_NOTIFY; if (GG_S_B(status) || GG_S_A(status)) { list_t l; for (l = spiedlist; l; l = l->next) { struct spied *s = l->data; if (s->uin == uin) { list_remove(&spiedlist, s, 1); break; } } } /* jeśli ktoś odchodzi albo dostajemy powiadomienie, że go nie ma (i go nie było)... */ if (GG_S_NA(status)) { /* jeśli go podglądamy, to sprawdźmy, czy się nie ukrywa */ if (group_member(u, "spied")) /* jeśli rozpoczęliśmy sprawdanie, to na razie nie informuj o zmianie stanu */ if (check_conn(u->uin) == 0) ignore_notify = 1; } #ifdef WITH_PYTHON for (l = modules; l; l = l->next) { struct module *m = l->data; PyObject *res; if (!m->handle_status) continue; res = PyObject_CallFunction(m->handle_status, "(isis)", uin, ((u && u->display) ? u->display : NULL), status, idescr); if (!res) PyErr_Print(); if (res && PyInt_Check(res)) { switch (PyInt_AsLong(res)) { case 0: Py_XDECREF(res); return; case 2: hide = 1; } } if (res && PyTuple_Check(res)) { unsigned char *newnick, *newdescr; if (PyArg_ParseTuple(res, "isis", &uin, &newnick, &status, &newdescr)) { descr = xstrdup(newdescr); } else PyErr_Print(); } Py_XDECREF(res); } #endif #define __USER_QUITING (GG_S_NA(status) && !GG_S_NA(u->status)) if (GG_S_BL(status) && !GG_S_BL(u->status)) { u->status = status; /* poza listą stanów */ if (!ignore_events) event_check(EVENT_BLOCKED, uin, NULL); } if (!descr) descr = xstrdup(idescr); /* zapamiętaj adres, port i protokół */ if (__USER_QUITING) { u->last_ip.s_addr = u->ip.s_addr; u->last_port = u->port; } if (ip) u->ip.s_addr = ip; if (port) u->port = port; if (version) u->protocol = version; if (image_size) u->image_size = image_size; /* jeśli status taki sam i ewentualnie opisy te same, ignoruj */ if (!GG_S_D(status) && (u->status == status)) { xfree(descr); return; } /* jeśli stan z opisem, a opisu brak, wpisz pusty tekst */ if (GG_S_D(status) && !descr) descr = xstrdup(""); if (descr) { unsigned char *tmp; for (tmp = descr; *tmp; tmp++) { /* usuwamy \r, interesuje nas tylko \n w opisie */ if (*tmp == 13) memmove(tmp, tmp + 1, strlen(tmp)); /* tabulacja na spacje */ if (*tmp == 9) *tmp = ' '; /* resztę poza \n zamieniamy na ? */ if (*tmp < 32 && *tmp != 10) *tmp = '?'; } cp_to_iso(descr); } if (GG_S_D(status) && (u->status == status) && u->descr && !strcmp(u->descr, descr)) { xfree(descr); return; } /* jesli ktoś nam znika, to sobie to zapamietujemy */ if (__USER_QUITING) { u->last_seen = time(NULL); xfree(u->last_descr); u->last_descr = xstrdup(u->descr); } #undef __USER_QUITING prev_status = u->status; for (s = st; s->status; s++) { /* jeśli nie ten, sprawdzaj dalej */ if (status != s->status) continue; if (GG_S_NA(s->status)) { memset(&u->ip, 0, sizeof(struct in_addr)); u->port = 0; u->protocol = 0; u->image_size = 0; } #define __SAME_GG_S(x, y) ((GG_S_A(x) && GG_S_A(y)) || (GG_S_B(x) && GG_S_B(y)) || (GG_S_I(x) && GG_S_I(y)) || (GG_S_NA(x) && GG_S_NA(y))) if (!ignore_events && (!config_events_delay || (time(NULL) - last_conn_event) >= config_events_delay)) { if ((descr && u->descr && strcmp(descr, u->descr)) || (!u->descr && descr)) event_check(EVENT_DESCR, uin, descr); if (!__SAME_GG_S(prev_status, status)) { if (!ignore_status && GG_S_NA(prev_status) && GG_S_A(s->status)) event_check(EVENT_ONLINE, uin, descr); else event_check(s->event, uin, descr); } } if (ignore_status_descr && GG_S_D(status)) { s--; status = s->status; if (__SAME_GG_S(prev_status, status)) break; } #undef __SAME_GG_S if ((ignore_status || ignore_notify) && !config_log_ignored) break; /* zaloguj */ if ((config_log_status == 1) && (!GG_S_D(s->status) || !descr)) put_log(uin, "status,%ld,%s,%s:%d,%s,%s\n", uin, ((u->display) ? u->display : ""), inet_ntoa(u->ip), u->port, log_timestamp(time(NULL)), s->log); if (config_log_status && GG_S_D(s->status) && descr) put_log(uin, "status,%ld,%s,%s:%d,%s,%s,%s\n", uin, ((u->display) ? u->display : ""), inet_ntoa(u->ip), u->port, log_timestamp(time(NULL)), s->log, descr); if (ignore_status || ignore_notify) break; /* jak dostępny lub zajęty i mamy go na liście, dopiszmy do taba * jak niedostępny, usuńmy. nie dotyczy osób spoza listy. */ if (!have_unknown) { if (GG_S_A(s->status) && config_completion_notify && u->display) add_send_nick(u->display); if (GG_S_B(s->status) && (config_completion_notify & 4) && u->display) add_send_nick(u->display); if (GG_S_I(s->status) && (config_completion_notify & 8) && u->display) add_send_nick(u->display); if (GG_S_NA(s->status) && (config_completion_notify & 2) && u->display) remove_send_nick(u->display); } /* wyświetlać na ekranie ? */ if (!(config_display_notify & ~4) || hide) break; if ((config_display_notify & ~4) == 2) { /* jeśli na zajęty, ignorujemy */ if (GG_S_B(s->status) && !GG_S_NA(prev_status)) break; /* jeśli na dostępny i nie był niedostępny, ignoruj */ if (GG_S_A(s->status) && !GG_S_NA(prev_status)) break; } /* czy ukrywać niedostępnych */ if (hide_notavail) { if (GG_S_NA(s->status) && GG_S_NA(u->status)) break; else if (time(NULL) - last_conn_event >= config_events_delay) hide_notavail = 0; } /* daj znać dżwiękiem */ if (config_beep && config_beep_notify && (!config_events_delay || (time(NULL) - last_conn_event) >= config_events_delay)) ui_beep(); /* i muzyczką */ if (config_sound_notify_file && strcmp(config_sound_notify_file, "") && (!config_events_delay || (time(NULL) - last_conn_event) >= config_events_delay)) play_sound(config_sound_notify_file); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init && config_contacts == 2) break; #endif /* no dobra, pokaż */ if (u->display || have_unknown) { char *tmp = xstrdup(descr), *p; char *target, *display; for (p = tmp; p && *p; p++) { if (*p == 13 || *p == 10) *p = '|'; } if (have_unknown) { target = (char *) itoa(uin); display = target; } else { target = u->display; display = (u->first_name) ? u->first_name : u->display; } if (config_status_window == 1) target = "__current"; else if (config_status_window == 2) target = "__status"; print_window(target, 0, s->format, format_user(uin), display, tmp); xfree(tmp); } break; } if (!ignore_status) { u->status = status; xfree(u->descr); u->descr = descr; ui_event("status", u->uin, ((u->display) ? u->display : ""), status, (ignore_status_descr) ? NULL : u->descr); } else xfree(descr); } /* * handle_notify() * * funkcja obsługuje listę obecnych. * * - e - opis zdarzenia. */ void handle_notify(struct gg_event *e) { struct gg_notify_reply *n; if (batch_mode) return; n = (e->type == GG_EVENT_NOTIFY) ? e->event.notify : e->event.notify_descr.notify; for (; n->uin; n++) { char *descr = (e->type == GG_EVENT_NOTIFY_DESCR) ? e->event.notify_descr.descr : NULL; handle_common(n->uin, n->status, descr, 0, n->remote_ip, n->remote_port, n->version, 0); } } /* * handle_notify60() * * funkcja obsługuje listę obecnych w wersji 6.0. * * - e - opis zdarzenia. */ void handle_notify60(struct gg_event *e) { int i; if (batch_mode) return; for (i = 0; e->event.notify60[i].uin; i++) handle_common(e->event.notify60[i].uin, e->event.notify60[i].status, e->event.notify60[i].descr, e->event.notify60[i].time, e->event.notify60[i].remote_ip, e->event.notify60[i].remote_port, e->event.notify60[i].version, e->event.notify60[i].image_size); } /* * handle_status() * * funkcja obsługuje zmianę stanu ludzi z listy kontaktów. * * - e - opis zdarzenia. */ void handle_status(struct gg_event *e) { if (batch_mode) return; handle_common(e->event.status.uin, e->event.status.status, e->event.status.descr, 0, 0, 0, 0, 0); } /* * handle_status60() * * funkcja obsługuje zmianę stanu ludzi z listy kontaktów w wersji 6.0. * * - e - opis zdarzenia. */ void handle_status60(struct gg_event *e) { if (batch_mode) return; handle_common(e->event.status60.uin, e->event.status60.status, e->event.status60.descr, e->event.status60.time, e->event.status60.remote_ip, e->event.status60.remote_port, e->event.status60.version, e->event.status60.image_size); } /* * handle_failure() * * funkcja obsługuje błędy przy połączeniu. * * - e - opis zdarzenia. */ void handle_failure(struct gg_event *e) { struct { int type; char *str; } reason[] = { { GG_FAILURE_RESOLVING, "conn_failed_resolving" }, { GG_FAILURE_CONNECTING, "conn_failed_connecting" }, { GG_FAILURE_INVALID, "conn_failed_invalid" }, { GG_FAILURE_READING, "conn_failed_disconnected" }, { GG_FAILURE_WRITING, "conn_failed_disconnected" }, { GG_FAILURE_PASSWORD, "conn_failed_password" }, { GG_FAILURE_404, "conn_failed_404" }, { GG_FAILURE_TLS, "conn_failed_tls" }, { GG_FAILURE_INTRUDER, "conn_failed_intruder" }, { GG_FAILURE_UNAVAILABLE, "conn_failed_unavailable" }, { 0, NULL } }; char *tmp = NULL; int i; for (i = 0; reason[i].type; i++) { if (reason[i].type == e->event.failure) { tmp = format_string(format_find(reason[i].str)); break; } } print("conn_failed", (tmp) ? tmp : "?"); xfree(tmp); /* jeśli się nie powiodło, usuwamy nasz serwer i łączymy przez huba */ if (config_server_save) { #ifdef __GG_LIBGADU_HAVE_OPENSSL if (sess->ssl && config_server && !strncasecmp(config_server, "tls", 3)) { xfree(config_server); config_server = xstrdup("tls"); } else #endif { xfree(config_server); config_server = NULL; } } list_remove(&watches, sess, 0); gg_logoff(sess); gg_free_session(sess); sess = NULL; userlist_clear_status(0); ekg_reconnect(); } /* * handle_success() * * funkcja obsługuje udane połączenia. * * - e - opis zdarzenia. */ void handle_success(struct gg_event *e) { struct in_addr addr; list_t l; if (config_reason && GG_S_D(config_status)) { char *r1, *r2; r1 = xstrmid(config_reason, 0, GG_STATUS_DESCR_MAXSIZE); r2 = xstrmid(config_reason, GG_STATUS_DESCR_MAXSIZE, -1); print("connected_descr", r1, r2); xfree(r2); xfree(r1); } else print("connected"); ui_event("connected"); userlist_send(); if (!msg_queue_flush()) print("queue_flush"); /* zapiszmy adres serwera */ if (config_server_save) { addr.s_addr = sess->server_addr; xfree(config_server); #ifdef __GG_LIBGADU_HAVE_OPENSSL if (sess->ssl) config_server = saprintf("tls:%s:%d", inet_ntoa(addr), sess->port); else #endif { if (sess->port != GG_DEFAULT_PORT) config_server = saprintf("%s:%d", inet_ntoa(addr), sess->port); else config_server = xstrdup(inet_ntoa(addr)); } } if (batch_mode && batch_line) { command_exec(NULL, batch_line, 0); xfree(batch_line); batch_line = NULL; } hide_notavail = 1; update_status(); update_status_myip(); last_conn_event = time(NULL); addr.s_addr = sess->server_addr; event_check(EVENT_CONNECTED, 0, inet_ntoa(addr)); list_destroy(spiedlist, 1); spiedlist = NULL; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (group_member(u, "spied")) check_conn(u->uin); } } /* * handle_event() * * funkcja obsługuje wszystkie zdarzenia dotyczące danej sesji GG. * * - e - opis zdarzenia. * * nie zwraca niczego. */ void handle_event(struct gg_session *s) { struct gg_event *e; struct handler *h; if (!(e = gg_watch_fd(sess))) { struct in_addr addr; print("conn_broken"); addr.s_addr = sess->server_addr; list_remove(&watches, sess, 0); gg_logoff(sess); gg_free_session(sess); sess = NULL; userlist_clear_status(0); ui_event("disconnected"); last_conn_event = time(NULL); event_check(EVENT_DISCONNECTED, 0, inet_ntoa(addr)); ekg_reconnect(); return; } for (h = handlers; h->type; h++) if (h->type == e->type) (h->handler)(e); gg_event_free(e); } /* * handle_pubdir() * * funkcja zajmująca się wszelkimi zdarzeniami http oprócz szukania. * * - h - delikwent. * * nie zwraca niczego. */ void handle_pubdir(struct gg_http *h) { struct gg_pubdir *s = NULL; const char *good = "", *bad = ""; if (!h) return; switch (h->type) { case GG_SESSION_REGISTER: good = "register"; bad = "register_failed"; break; case GG_SESSION_UNREGISTER: good = "unregister"; bad = "unregister_failed"; break; case GG_SESSION_PASSWD: good = "passwd"; bad = "passwd_failed"; break; case GG_SESSION_REMIND: good = "remind"; bad = "remind_failed"; break; } if (gg_pubdir_watch_fd(h) || h->state == GG_STATE_ERROR) { print(bad, http_error_string(h->error)); goto fail; } if (h->state != GG_STATE_DONE) return; if (!(s = h->data) || !s->success) { print(bad, http_error_string(h->error)); goto fail; } if (h->type == GG_SESSION_PASSWD) { xfree(config_password); config_password = reg_password; reg_password = NULL; if (reg_email) { xfree(config_email); config_email = reg_email; reg_email = NULL; } } if (h->type == GG_SESSION_REGISTER) { if (!s->uin) { print("register_failed", ""); goto fail; } if (!config_uin && !config_password && reg_password && !config_email && reg_email) { config_uin = s->uin; changed_uin("uin"); config_password = reg_password; reg_password = NULL; config_email = reg_email; reg_email = NULL; } registered_today = 1; } if (h->type == GG_SESSION_UNREGISTER) { if (!s->uin) { print("unregister_failed", ""); goto fail; } if (s->uin == config_uin) { config_uin = 0; config_password = 0; config_changed = 1; command_exec(NULL, "disconnect", 0); print("no_config"); } } print(good, itoa(s->uin)); fail: list_remove(&watches, h, 0); if (h->type == GG_SESSION_REGISTER || h->type == GG_SESSION_PASSWD) { xfree(reg_password); reg_password = NULL; xfree(reg_email); reg_email = NULL; } gg_free_pubdir(h); } #ifdef HAVE_LIBUNGIF /* * token_gif_load() * * Wczytuje token z pliku gif. Zwraca -1 jeśli się nie uda (wtedy w token->data * będzie komunikat o błędzie) lub 0. Jeśli token->pal_sz != 0 to znaczy, że * token zawiera paletę barw, w której należy sprawdzać piksele (w kolejności * r, g i b). Rozmiar palety w bajtach to pal_sz * 3. * * - fname - nazwa pliku z gifem do wczytania * - token - wskaźnik do struktury na token */ int token_gif_load (char *fname, struct token_t *token) { char errbuf[512]; GifFileType *file; #ifdef TOKEN_GIF_PAL ColorMapObject *pal; #endif int fd; fd = open(fname, O_RDONLY); if (fd == -1) { snprintf(errbuf, sizeof(errbuf), "open(%s): %m", fname); goto err; } if (!(file = DGifOpenFileHandle(fd))) { snprintf(errbuf, sizeof(errbuf), "DGifOpenFileHandle(): %d", GifLastError()); goto err2; } if (file->SWidth <= 0 || file->SWidth > 1024 || file->SHeight <= 0 || file->SHeight > 1024) { snprintf(errbuf, sizeof(errbuf), "Invalid image size: %d,%d", file->SWidth, file->SHeight); goto err3; } if (DGifSlurp(file) != GIF_OK) { snprintf(errbuf, sizeof(errbuf), "DGifSlurp(): %d", GifLastError()); goto err3; } if (file->ImageCount != 1) { snprintf(errbuf, sizeof(errbuf), "ImageCount = %d", file->ImageCount); goto err3; } #ifdef TOKEN_GIF_PAL token->pal = NULL; token->pal_sz = 0; pal = file->SavedImages[0].ImageDesc.ColorMap; if (!pal) pal = file->SColorMap; if (pal) { token->pal_sz = pal->ColorCount; token->pal = (unsigned char *) xmalloc(token->pal_sz * 3); memcpy(token->pal, pal->Colors, pal->ColorCount); } #endif token->sx = file->SavedImages[0].ImageDesc.Width; token->sy = file->SavedImages[0].ImageDesc.Height; token->data = (unsigned char *) xmalloc(token->sx * token->sy); memcpy(token->data, file->SavedImages[0].RasterBits, token->sx * token->sy); DGifCloseFile(file); return 0; err3: DGifCloseFile(file); err2: close(fd); err: token->data = (unsigned char *) xstrdup(errbuf); return -1; } /* * token_gif_free() * * Zwalnia struktury zajmowane przez token (NIE samą token_t). * * - token - wskaźnik do struktury z danymi do zwolnienia */ void token_gif_free (struct token_t *token) { if (token->data) xfree(token->data); #ifdef TOKEN_GIF_PAL if (token->pal) xfree(token->pal); #endif token->data = NULL; #ifdef TOKEN_GIF_PAL token->pal = NULL; #endif } /* * token_gif_get_pixel() * * Pobiera piksel z podanej pozycji. Jeśli pozycja jest poza zakresem, zwraca * podany kolor tła. * * - token - wskaźnik na strukturę opisującą token * - x, y - pozyzja piksela * - backgr_color - numer koloru tła */ char token_gif_get_pixel (struct token_t *token, size_t x, size_t y, unsigned char backgr_color) { return (x < 0 || y < 0 || x >= token->sx || y >= token->sy) ? backgr_color : token->data[y * token->sx + x]; } /* * token_gif_strip() * * Usuwa z obrazka wszystko, czego nie potrzebujemy (linie, pojedyncze * piksele i antyaliasing czcionki). * * - token - wskaźnik na strukturę opisującą token */ void token_gif_strip (struct token_t *token) { unsigned char *new_data; size_t i; size_t x, y; unsigned char backgr_color = 0; size_t backgr_counts[256]; /* Usuwamy wszystkie samotne piksele. Piksel jest uznawany za samotny * wtedy, kiedy nie ma w jego najbliższym otoczeniu, obejmującym 8 * pikseli dookoła niego, przynajmniej trzech pikseli o tym samym * kolorze. To usuwa kropki i pojedyncze linie dodawane w celu * zaciemnienia obrazu tokena oraz anty-aliasing czcionek w znakach. * Otoczenie pikseli brzegowych jest uznawane za kolor tła tak, jakby * tło zostało rozszerzone. */ /* Najpierw sprawdzamy kolor tła. To piksel, którego jest najwięcej. */ for (i = 0; i < 256; i++) backgr_counts[i] = 0; for (i = 0; i < token->sx * token->sy; i++) { unsigned char pixel = token->data[i]; if (++backgr_counts[pixel] > backgr_counts[backgr_color]) backgr_color = pixel; } new_data = (unsigned char *) xmalloc(token->sx * token->sy); for (y = 0; y < token->sy; y++) for (x = 0; x < token->sx; x++) { int dx, dy; char new_pixel = backgr_color; if (token->data[y * token->sx + x] != backgr_color) { int num_pixels = 0; /* num_pixels przechowuje liczbę pikseli w otoczeniu * badanego piksela (wliczając sam badany piksel) * o tym samym kolorze, co badany piksel. */ for (dy = -1; dy <= 1; dy++) for (dx = -1; dx <= 1; dx++) if (token_gif_get_pixel(token, x + dx, y + dy, backgr_color) == token->data[y * token->sx + x]) num_pixels++; if (num_pixels >= 4) /* 4, bo razem z badanym */ new_pixel = token->data[y * token->sx + x]; } new_data[y * token->sx + x] = new_pixel; // ? 1 : 0; } xfree(token->data); token->data = new_data; } /* * token_gif_strip_txt * * Usuwa z podanego bufora tekstowego puste linie na górze i na dole. * Zwraca nowo zaalokowany bufor. * * - buf - bufor do stripnięcia */ char *token_gif_strip_txt (char *buf) { char *new_buf = NULL; size_t start, end, len; len = strlen(buf); for (start = 0; start < len; start++) if (buf[start] != 0x20 && buf[start] != '\n') break; if (!buf[start]) return NULL; while (start && buf[start] != '\n') start--; if (start) start++; for (end = 0; end < len; end++) if (buf[len - 1 - end] != 0x20 && buf[len - 1 - end] != '\n') break; end = len - 1 - end; end--; if (end < start) return NULL; new_buf = (char *) xmalloc(end - start + 2); memcpy(new_buf, buf + start, end - start); new_buf[end - start - 1] = '\n'; new_buf[end - start] = 0; return new_buf; } /* * token_gif_to_txt() * * Konwertuje token do postaci tekstowej. Zwraca bufor tekstowy z tokenem * obróconym tak, żeby lepiej zmieścić się na ekranie. * * - token - wskaźnik na strukturę opisującą token */ char *token_gif_to_txt (struct token_t *token) { char *buf, *bptr; size_t x, y; #ifdef TOKEN_GIF_PAL size_t i; unsigned char min_rgb[3] = {255, 255, 255}; unsigned char max_rgb[3] = {0, 0, 0}; unsigned char delta_rgb[3] = {255, 255, 255}; #endif static const char chars[] = " !@#$&*:;-=+?"; char mappings[256]; int cur_char = 0; /* Kolejny znaczek z chars[]. */ memset(mappings, 0, sizeof(mappings)); buf = bptr = (char *) xmalloc(token->sx * (token->sy + 1) + 1); #ifdef TOKEN_GIF_PAL for (i = 0; i < token->sx * token->sy; i++) { unsigned char ofs = token->data[i]; unsigned char *pent; size_t pent_i; if (ofs >= token->pal_sz) continue; pent = token->pal + ofs * 3; for (pent_i = 0; pent_i < 3; pent_i++) { if (pent[pent_i] < min_rgb[pent_i]) min_rgb[pent_i] = pent[pent_i]; if (pent[pent_i] > max_rgb[pent_i]) max_rgb[pent_i] = pent[pent_i]; } } for (i = 0; i < 3; i++) delta_rgb[i] = max_rgb[i] - min_rgb[i]; for (i = 0; i < ((token->pal_sz < 256) ? token->pal_sz : 256); i++) { char rgb[3]; size_t ri; for (ri = 0; ri < 3; ri++) rgb[ri] = ((int) token->pal[i * 3 + ri] - min_rgb[ri]) * 255 / delta_rgb[ri]; intens[i] = (33 * rgb[0] + 59 * rgb[1] + 11 * rgb[2]) >= 50 ? 0 : 1; } #endif for (x = 0; x < token->sx; x++) { for (y = 0; y < token->sy; y++) { unsigned char reg; reg = token->data[y * token->sx + (token->sx - 1 - x)]; /* Mamy już mapowanie dla tego koloru? */ if (reg && !mappings[reg]) { mappings[reg] = ++cur_char; /* Podzielenie przez drugi sizeof nie jest * potrzebne, ale gdyby ktoś kiedyś chciał * wpaść na pomysł zmiany typu draw_chars, * to dla bezpieczeństwa lepiej dać. */ cur_char %= sizeof(chars) / sizeof(*chars) - 1; } *bptr++ = reg ? chars[(size_t) mappings[(size_t) reg]] : 0x20; } *bptr++ = '\n'; } *bptr = 0; bptr = token_gif_strip_txt(buf); if (bptr) { xfree(buf); return bptr; } return buf; } #endif #ifdef HAVE_LIBJPEG /* * token_check() * * funkcja sprawdza czy w danym miejscu znajduje się zaproponowany znaczek * * - n - numer od 0 do 15 (znaczki od 0 do f) * - x, y - współrzędne znaczka w tablicy ocr */ static int token_check(int nr, int x, int y, const char *ocr, int maxx, int maxy) { int i; for (i = nr * token_char_height; i < (nr + 1) * token_char_height; i++, y++) { int j, xx = x; for (j = 0; token_id[i][j] && j + xx < maxx; j++, xx++) { if (token_id[i][j] != ocr[y * (maxx + 1) + xx]) return 0; } } gg_debug(GG_DEBUG_MISC, "token_check(nr=%d,x=%d,y=%d,ocr=%p,maxx=%d,maxy=%d\n", nr, x, y, ocr, maxx, maxy); return 1; } /* * token_ocr() * * zwraca treść tokenu */ char *token_ocr(const char *ocr, int width, int height, int length) { int x, y, count = 0; char *token; token = xmalloc(length + 1); memset(token, 0, length + 1); for (x = 0; x < width; x++) { for (y = 0; y < height - token_char_height; y++) { int result = 0, token_part = 0; do result = token_check(token_part++, x, y, ocr, width, height); while (!result && token_part < 16); if (result && count < length) token[count++] = token_id_char[token_part - 1]; } } if (count == length) return token; xfree(token); return NULL; } struct ekg_jpeg_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; void ekg_jpeg_error_exit(j_common_ptr j) { struct ekg_jpeg_error_mgr *e = (struct ekg_jpeg_error_mgr *) j->err; /* Return control to the setjmp point */ longjmp(e->setjmp_buffer, 1); } #endif /* * handle_token() * * funkcja zajmująca się zdarzeniami związanymi z pobieraniem tokenu. * * - h - delikwent. * * nie zwraca niczego. */ void handle_token(struct gg_http *h) { struct gg_token *t = NULL; char *file = NULL; int fd; if (!h) return; if (gg_token_watch_fd(h) || h->state == GG_STATE_ERROR) { print("token_failed", http_error_string(h->error)); goto fail; } if (h->state != GG_STATE_DONE) return; if (!(t = h->data) || !h->body) { print("token_failed", http_error_string(h->error)); goto fail; } xfree(last_tokenid); last_tokenid = xstrdup(t->tokenid); #ifdef HAVE_MKSTEMP file = saprintf("%s/token.XXXXXX", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp"); if ((fd = mkstemp(file)) == -1) { print("token_failed", strerror(errno)); goto fail; } if ((write(fd, h->body, h->body_size) != h->body_size) || (close(fd) != 0)) { print("token_failed", strerror(errno)); close(fd); unlink(file); goto fail; } #ifdef HAVE_LIBUNGIF if (config_display_token) { struct token_t token; char *buf; if (token_gif_load(file, &token) == -1) { print("token_failed", token.data); xfree (token.data); goto fail; } token_gif_strip (&token); buf = token_gif_to_txt(&token); print("token_start"); print("token_body", buf); print("token_end"); xfree (buf); token_gif_free (&token); goto fail; } #endif #ifdef HAVE_LIBJPEG if (config_display_token) { struct jpeg_decompress_struct j; struct ekg_jpeg_error_mgr e; JSAMPROW buf[1]; int size; char *token, *tmp; FILE *f; int h = 0; if (!(f = fopen(file, "rb"))) { print("token_failed", strerror(errno)); goto fail; } j.err = jpeg_std_error(&e.pub); e.pub.error_exit = ekg_jpeg_error_exit; /* Establish the setjmp return context for ekg_jpeg_error_exit to use. */ if (setjmp(e.setjmp_buffer)) { char buf[JMSG_LENGTH_MAX]; /* If we ended up over here, then it means some call below called longjmp. */ (e.pub.format_message)((j_common_ptr)&j, buf); print("token_failed", buf); jpeg_destroy_decompress(&j); fclose(f); goto fail; } jpeg_create_decompress(&j); jpeg_stdio_src(&j, f); jpeg_read_header(&j, TRUE); jpeg_start_decompress(&j); size = j.output_width * j.output_components; buf[0] = xmalloc(size); token = xmalloc((j.output_width + 1) * j.output_height); while (j.output_scanline < j.output_height) { int i; jpeg_read_scanlines(&j, buf, 1); for (i = 0; i < j.output_width; i++, h++) token[h] = (buf[0][i*3] + buf[0][i*3+1] + buf[0][i*3+2] < 384) ? '#' : '.'; token[h++] = 0; } if (!(tmp = token_ocr(token, j.output_width, j.output_height, t->length))) { int i; for (i = 0; i < j.output_height; i++) print("token_body", &token[i * (j.output_width + 1)]); } else { print("token_ocr", tmp); xfree(tmp); } xfree(token); jpeg_finish_decompress(&j); jpeg_destroy_decompress(&j); xfree(buf[0]); fclose(f); unlink(file); } else #endif /* HAVE_LIBJPEG */ { char *file2 = saprintf("%s.gif", file); if (rename(file, file2) == -1) print("token", file); else print("token", file2); xfree(file2); } #else /* HAVE_MKSTEMP */ print("token_unsupported"); #endif /* HAVE_MKSTEMP */ fail: ; /* * to nie jest żart, bez tej pustej instrukcji zdarza się, * że kolejny ifdef nie jest spełniony... */ #ifdef HAVE_MKSTEMP unlink(file); xfree(file); #endif list_remove(&watches, h, 0); gg_token_free(h); } /* * handle_userlist() * * funkcja zajmująca się zdarzeniami userlisty. * * - h - delikwent. * * nie zwraca niczego. */ void handle_userlist(struct gg_event *e) { switch (e->event.userlist.type) { case GG_USERLIST_GET_REPLY: { if (!userlist_get_config) print("userlist_get_ok"); else print("userlist_config_get_ok"); if (e->event.userlist.reply) { list_t l; if (config_userlist_backup) { if (userlist_get_config) { const char *filename; char tmp[32]; snprintf(tmp, sizeof(tmp), "config.%d", (int) getpid()); if ((filename = prepare_path(tmp, 1)) && !config_write(filename)) print("config_backup_ok"); else { print("config_backup_failed"); break; } } if (!userlist_write(1)) print("userlist_backup_ok"); else { print("userlist_backup_failed"); break; } } for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (sess) gg_remove_notify_ex(sess, u->uin, userlist_type(u)); } cp_to_iso(e->event.userlist.reply); userlist_set(e->event.userlist.reply, userlist_get_config); userlist_send(); update_status(); update_status_myip(); for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (u->display) ui_event("userlist_changed", itoa(u->uin), u->display, NULL); } config_changed = 1; } break; } case GG_USERLIST_PUT_REPLY: { switch (userlist_put_config) { case 0: print("userlist_put_ok"); break; case 1: print("userlist_config_put_ok"); break; case 2: print("userlist_clear_ok"); break; case 3: print("userlist_config_clear_ok"); break; } break; } } } /* * handle_disconnect() * * funkcja obsługuje ostrzeżenie o rozłączeniu. * * - e - opis zdarzenia. * * nie zwraca niczego. */ void handle_disconnect(struct gg_event *e) { struct in_addr addr; print("conn_disconnected"); ui_event("disconnected"); addr.s_addr = sess->server_addr; gg_logoff(sess); /* a zobacz.. może się uda ;> */ list_remove(&watches, sess, 0); gg_free_session(sess); sess = NULL; userlist_clear_status(0); update_status(); last_conn_event = time(NULL); event_check(EVENT_CONNECTIONLOST, 0, inet_ntoa(addr)); } /* * fix_filename() * * poprawia nazwę pliku do zapisania na dysku, usuwając potencjalnie * niebezpieczne znaki - elementy ścieżki oraz znaki o kodach < 32. * używane przez obsługę dcc oraz obrazków. * * - name - nazwa */ static void fix_filename (unsigned char *name) { unsigned char *p; for (p = name; *p; p++) if (*p < 32 || *p == '\\' || *p == '/') *p = '_'; if (name[0] == '.') name[0] = '_'; } /* * find_transfer() * * znajduje strukturę ,,transfer'' dotyczącą danego połączenia. * * - d - struktura gg_dcc lub gg_dcc7, której szukamy. * * wskaźnik do struktury ,,transfer'' lub NULL, jeśli nie znalazł. */ static struct transfer *find_transfer(void *d) { list_t l; for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if (t->dcc == d || t->dcc7 == d) return t; } return NULL; } /* * remove_transfer() * * usuwa z listy transferów ten, który dotyczy podanego połączenia dcc. * * - d - połączenie. * * nie zwraca nic. */ void remove_transfer(void *d) { struct transfer *t = find_transfer(d); if (t) { xfree(t->filename); list_remove(&transfers, t, 1); } } /* * check_dcc_limit() * * sprawdza czy nie przekroczono limitu połączeń bezpośrednich. jeśli tak, * wyłącza je i zwalnia strukturę gg_dcc przekazaną w zdarzeniu. * * - e - struktura zdarzenia. * * 0/-1. */ static int check_dcc_limit(struct gg_event *e) { int c, t = 60; char *tmp; if (!config_dcc_limit) return 0; if ((tmp = strchr(config_dcc_limit, '/'))) t = atoi(tmp + 1); c = atoi(config_dcc_limit); if (time(NULL) - dcc_limit_time > t) { dcc_limit_time = time(NULL); dcc_limit_count = 0; } dcc_limit_count++; if (dcc_limit_count > c) { print("dcc_limit"); config_dcc = 0; changed_dcc("dcc"); dcc_limit_time = 0; dcc_limit_count = 0; if (e->type == GG_EVENT_DCC_NEW) { gg_dcc_free(e->event.dcc_new); e->event.dcc_new = NULL; } if (e->type == GG_EVENT_DCC7_NEW) { gg_dcc7_free(e->event.dcc7_new); e->event.dcc7_new = NULL; } return -1; } return 0; } /* * handle_dcc() * * funkcja zajmuje się obsługą wszystkich zdarzeń związanych z DCC. * * - d - struktura danego połączenia. * * nie zwraca niczego. */ void handle_dcc(struct gg_dcc *d) { struct gg_event *e; struct transfer *t, tt; list_t l; if (ignored_check(d->peer_uin) & IGNORE_DCC) { remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); return; } if (!(e = gg_dcc_watch_fd(d))) { print("dcc_error", strerror(errno)); if (d->type != GG_SESSION_DCC_SOCKET) { remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); } return; } switch (e->type) { case GG_EVENT_DCC_NEW: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_NEW\n"); if (check_dcc_limit(e) == -1) break; list_add(&watches, e->event.dcc_new, 0); e->event.dcc_new = NULL; break; case GG_EVENT_DCC_CLIENT_ACCEPT: { struct userlist *u; gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_CLIENT_ACCEPT\n"); if (!(u = userlist_find(d->peer_uin, NULL)) || config_uin != d->uin) { gg_debug(GG_DEBUG_MISC, "## unauthorized client (uin=%ld), closing connection\n", d->peer_uin); list_remove(&watches, d, 0); gg_free_dcc(d); return; } if (config_dcc_filter && d->remote_addr != u->ip.s_addr) { char tmp[20]; snprintf(tmp, sizeof(tmp), "%s", inet_ntoa(*((struct in_addr*) &d->remote_addr))); print("dcc_spoof", format_user(d->peer_uin), inet_ntoa(u->ip), tmp); } t = find_transfer(d); if (t) { t->start = time(NULL); if (t->start == -1) t->start = 0; } break; } case GG_EVENT_DCC_CALLBACK: { int found = 0; gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_CALLBACK\n"); for (l = transfers; l; l = l->next) { struct transfer *t = l->data; gg_debug(GG_DEBUG_MISC, "// transfer id=%d, uin=%d, type=%d\n", t->id, t->uin, t->type); if (t->uin == d->peer_uin && !t->dcc) { gg_debug(GG_DEBUG_MISC, "## found transfer, uin=%d, type=%d\n", d->peer_uin, t->type); t->dcc = d; gg_dcc_set_type(d, t->type); found = 1; break; } } if (!found) { gg_debug(GG_DEBUG_MISC, "## connection from %d not found\n", d->peer_uin); list_remove(&watches, d, 0); gg_dcc_free(d); } break; } case GG_EVENT_DCC_NEED_FILE_INFO: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_NEED_FILE_INFO\n"); for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if (t->dcc == d) { char *remote; remote = xstrdup(t->filename); iso_to_cp(remote); if (gg_dcc_fill_file_info2(d, remote, t->filename) == -1) { gg_debug(GG_DEBUG_MISC, "## gg_dcc_fill_file_info() failed (%s)\n", strerror(errno)); print("dcc_open_error", t->filename); remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); xfree(remote); break; } xfree(remote); break; } } break; case GG_EVENT_DCC_NEED_FILE_ACK: { char *path; struct stat st; gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_NEED_FILE_ACK\n"); /* żeby nie sprawdzało, póki luser nie odpowie */ list_remove(&watches, d, 0); if (!(t = find_transfer(d))) { tt.uin = d->peer_uin; tt.type = GG_SESSION_DCC_GET; tt.filename = NULL; tt.dcc = d; tt.id = transfer_id(); t = list_add(&transfers, &tt, sizeof(tt)); } fix_filename(d->file_info.filename); t->type = GG_SESSION_DCC_GET; t->filename = xstrdup(d->file_info.filename); cp_to_iso(t->filename); print("dcc_get_offer", format_user(t->uin), t->filename, itoa(d->file_info.size), itoa(t->id)); if (config_dcc_dir) path = saprintf("%s/%s", config_dcc_dir, t->filename); else path = xstrdup(t->filename); if (!stat(path, &st) && st.st_size < d->file_info.size) print("dcc_get_offer_resume", format_user(t->uin), t->filename, itoa(d->file_info.size), itoa(t->id)); xfree(path); if (!(ignored_check(t->uin) & IGNORE_EVENTS)) event_check(EVENT_DCC, t->uin, t->filename); break; } case GG_EVENT_DCC_NEED_VOICE_ACK: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_NEED_VOICE_ACK\n"); #ifdef HAVE_VOIP /* żeby nie sprawdzało, póki luser nie odpowie */ list_remove(&watches, d, 0); if (!(t = find_transfer(d))) { tt.uin = d->peer_uin; tt.type = GG_SESSION_DCC_VOICE; tt.filename = NULL; tt.dcc = d; tt.id = transfer_id(); if (!(t = list_add(&transfers, &tt, sizeof(tt)))) { gg_free_dcc(d); break; } } t->type = GG_SESSION_DCC_VOICE; print("dcc_voice_offer", format_user(t->uin), itoa(t->id)); #else list_remove(&watches, d, 0); remove_transfer(d); gg_free_dcc(d); #endif break; case GG_EVENT_DCC_VOICE_DATA: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_VOICE_DATA\n"); #ifdef HAVE_VOIP voice_open(); voice_play(e->event.dcc_voice_data.data, e->event.dcc_voice_data.length, 0); #endif break; case GG_EVENT_DCC_DONE: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_DONE\n"); if (!(t = find_transfer(d))) { gg_free_dcc(d); break; } event_check(EVENT_DCCFINISH, t->uin, t->filename); print((t->dcc->type == GG_SESSION_DCC_SEND) ? "dcc_done_send" : "dcc_done_get", format_user(t->uin), t->filename); remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); break; case GG_EVENT_DCC_ERROR: { struct in_addr addr; unsigned short port = d->remote_port; char *tmp; addr.s_addr = d->remote_addr; if (d->peer_uin) { struct userlist *u = userlist_find(d->peer_uin, NULL); if (!addr.s_addr && u) { addr.s_addr = u->ip.s_addr; port = u->port; } tmp = saprintf("%s (%s:%d)", format_user(d->peer_uin), inet_ntoa(addr), port); } else tmp = saprintf("%s:%d", inet_ntoa(addr), port); switch (e->event.dcc_error) { case GG_ERROR_DCC_HANDSHAKE: print("dcc_error_handshake", tmp); break; case GG_ERROR_DCC_NET: print("dcc_error_network", tmp); break; case GG_ERROR_DCC_REFUSED: print("dcc_error_refused", tmp); break; default: print("dcc_error_unknown", tmp); } xfree(tmp); #ifdef HAVE_VOIP if (d->type == GG_SESSION_DCC_VOICE) voice_close(); #endif /* HAVE_VOIP */ remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); break; } } gg_event_free(e); return; } /* * handle_dcc7() * * funkcja zajmuje się obsługą zdarzeń związanych z DCC 7.x. * * - d - struktura danego połączenia. * * nie zwraca niczego. */ void handle_dcc7(struct gg_dcc7 *d) { struct gg_event *e; struct transfer *t; if (ignored_check(d->peer_uin) & IGNORE_DCC) { remove_transfer(d); list_remove(&watches, d, 0); gg_dcc7_free(d); return; } if (!(e = gg_dcc7_watch_fd(d))) { print("dcc_error", strerror(errno)); if (d->type != GG_SESSION_DCC7_SOCKET) { remove_transfer(d); list_remove(&watches, d, 0); gg_dcc7_free(d); } return; } switch (e->type) { #if 0 case GG_EVENT_DCC_CLIENT_ACCEPT: { struct userlist *u; gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_CLIENT_ACCEPT\n"); if (!(u = userlist_find(d->peer_uin, NULL)) || config_uin != d->uin) { gg_debug(GG_DEBUG_MISC, "## unauthorized client (uin=%ld), closing connection\n", d->peer_uin); list_remove(&watches, d, 0); gg_free_dcc(d); return; } if (config_dcc_filter && d->remote_addr != u->ip.s_addr) { char tmp[20]; snprintf(tmp, sizeof(tmp), "%s", inet_ntoa(*((struct in_addr*) &d->remote_addr))); print("dcc_spoof", format_user(d->peer_uin), inet_ntoa(u->ip), tmp); } t = find_transfer(d); if (t) { t->start = time(NULL); if (t->start == -1) t->start = 0; } break; } case GG_EVENT_DCC_CALLBACK: { int found = 0; gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_CALLBACK\n"); for (l = transfers; l; l = l->next) { struct transfer *t = l->data; gg_debug(GG_DEBUG_MISC, "// transfer id=%d, uin=%d, type=%d\n", t->id, t->uin, t->type); if (t->uin == d->peer_uin && !t->dcc) { gg_debug(GG_DEBUG_MISC, "## found transfer, uin=%d, type=%d\n", d->peer_uin, t->type); t->dcc = d; gg_dcc_set_type(d, t->type); found = 1; break; } } if (!found) { gg_debug(GG_DEBUG_MISC, "## connection from %d not found\n", d->peer_uin); list_remove(&watches, d, 0); gg_dcc_free(d); } break; } case GG_EVENT_DCC_NEED_FILE_INFO: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_NEED_FILE_INFO\n"); for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if (t->dcc == d) { char *remote; remote = xstrdup(t->filename); iso_to_cp(remote); if (gg_dcc_fill_file_info2(d, remote, t->filename) == -1) { gg_debug(GG_DEBUG_MISC, "## gg_dcc_fill_file_info() failed (%s)\n", strerror(errno)); print("dcc_open_error", t->filename); remove_transfer(d); list_remove(&watches, d, 0); gg_free_dcc(d); xfree(remote); break; } xfree(remote); break; } } break; case GG_EVENT_DCC_NEED_VOICE_ACK: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_NEED_VOICE_ACK\n"); #ifdef HAVE_VOIP /* żeby nie sprawdzało, póki luser nie odpowie */ list_remove(&watches, d, 0); if (!(t = find_transfer(d))) { tt.uin = d->peer_uin; tt.type = GG_SESSION_DCC_VOICE; tt.filename = NULL; tt.dcc = d; tt.id = transfer_id(); if (!(t = list_add(&transfers, &tt, sizeof(tt)))) { gg_free_dcc(d); break; } } t->type = GG_SESSION_DCC_VOICE; print("dcc_voice_offer", format_user(t->uin), itoa(t->id)); #else list_remove(&watches, d, 0); remove_transfer(d); gg_free_dcc(d); #endif break; case GG_EVENT_DCC_VOICE_DATA: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC_VOICE_DATA\n"); #ifdef HAVE_VOIP voice_open(); voice_play(e->event.dcc_voice_data.data, e->event.dcc_voice_data.length, 0); #endif break; #endif case GG_EVENT_DCC7_DONE: gg_debug(GG_DEBUG_MISC, "## GG_EVENT_DCC7_DONE\n"); if (!(t = find_transfer(d))) { gg_dcc7_free(d); break; } event_check(EVENT_DCCFINISH, t->uin, t->filename); print((t->dcc7->type == GG_SESSION_DCC7_SEND) ? "dcc_done_send" : "dcc_done_get", format_user(t->uin), t->filename); remove_transfer(d); list_remove(&watches, d, 0); gg_dcc7_free(d); break; case GG_EVENT_DCC7_ERROR: { struct in_addr addr; unsigned short port = d->remote_port; char *tmp; addr.s_addr = d->remote_addr; if (d->peer_uin) { struct userlist *u = userlist_find(d->peer_uin, NULL); if (!addr.s_addr && u) { addr.s_addr = u->ip.s_addr; port = u->port; } tmp = saprintf("%s (%s:%d)", format_user(d->peer_uin), inet_ntoa(addr), port); } else tmp = saprintf("%s:%d", inet_ntoa(addr), port); switch (e->event.dcc7_error) { case GG_ERROR_DCC7_HANDSHAKE: print("dcc_error_handshake", tmp); break; case GG_ERROR_DCC7_NET: print("dcc_error_network", tmp); break; case GG_ERROR_DCC7_REFUSED: print("dcc_error_refused", tmp); break; default: print("dcc_error_unknown", tmp); } xfree(tmp); #ifdef HAVE_VOIP if (d->type == GG_SESSION_DCC7_VOICE) voice_close(); #endif /* HAVE_VOIP */ remove_transfer(d); list_remove(&watches, d, 0); gg_dcc7_free(d); break; } } gg_event_free(e); return; } /* * handle_voice() * * obsługa danych przychodzących z urządzenia wejściowego. * * - c - struktura opisująca urządzenie wejściowe. * * brak. */ void handle_voice(struct gg_common *c) { #ifdef HAVE_VOIP list_t l; struct gg_dcc *d = NULL; char buf[GG_DCC_VOICE_FRAME_LENGTH_505]; /* dłuższy z buforów */ int length = GG_DCC_VOICE_FRAME_LENGTH; for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if (t->type == GG_SESSION_DCC_VOICE && t->dcc && (t->dcc->state == GG_STATE_READING_VOICE_HEADER || t->dcc->state == GG_STATE_READING_VOICE_SIZE || t->dcc->state == GG_STATE_READING_VOICE_DATA)) { d = t->dcc; length = (t->protocol >= 0x1b) ? GG_DCC_VOICE_FRAME_LENGTH_505 : GG_DCC_VOICE_FRAME_LENGTH; break; } } /* póki nie mamy połączenia, i tak czytamy z /dev/dsp */ if (!d) { voice_record(buf, length, 1); /* XXX błędy */ return; } else { voice_record(buf, length, 0); /* XXX błędy */ if (config_audio_device && config_audio_device[0] != '-') gg_dcc_voice_send(d, buf, length); /* XXX błędy */ } #endif /* HAVE_VOIP */ } /* * handle_search50() * * zajmuje się obsługą wyniku przeszukiwania katalogu publicznego. * * - e - opis zdarzenia */ void handle_search50(struct gg_event *e) { gg_pubdir50_t res = e->event.pubdir50; int i, count, all = 0; list_t l; uin_t last_uin = 0; if ((count = gg_pubdir50_count(res)) < 1) { print("search_not_found"); return; } gg_debug(GG_DEBUG_MISC, "handle_search50, count = %d\n", gg_pubdir50_count(res)); for (l = searches; l; l = l->next) { gg_pubdir50_t req = l->data; if (gg_pubdir50_seq(req) == gg_pubdir50_seq(res)) { all = 1; break; } } for (i = 0; i < count; i++) { const char *__fmnumber = gg_pubdir50_get(res, i, "fmnumber"); const char *uin = (__fmnumber) ? __fmnumber : "?"; const char *__firstname = gg_pubdir50_get(res, i, "firstname"); char *firstname = xstrdup((__firstname) ? __firstname : ""); const char *__lastname = gg_pubdir50_get(res, i, "lastname"); char *lastname = xstrdup((__lastname) ? __lastname : ""); const char *__nickname = gg_pubdir50_get(res, i, "nickname"); char *nickname = xstrdup((__nickname) ? __nickname : ""); const char *__fmstatus = gg_pubdir50_get(res, i, "fmstatus"); int status = (__fmstatus) ? atoi(__fmstatus) : GG_STATUS_NOT_AVAIL; const char *__birthyear = gg_pubdir50_get(res, i, "birthyear"); const char *birthyear = (__birthyear && strcmp(__birthyear, "0")) ? __birthyear : "-"; const char *__city = gg_pubdir50_get(res, i, "city"); char *city = xstrdup((__city) ? __city : ""); char *name, *active, *gender; const char *target = NULL; cp_to_iso(firstname); cp_to_iso(lastname); cp_to_iso(nickname); cp_to_iso(city); if (count == 1 && !all) { xfree(last_search_first_name); xfree(last_search_last_name); xfree(last_search_nickname); last_search_first_name = xstrdup(firstname); last_search_last_name = xstrdup(lastname); last_search_nickname = xstrdup(nickname); last_search_uin = atoi(uin); } name = saprintf("%s %s", firstname, lastname); #define __format(x) ((count == 1 && !all) ? "search_results_single" x : "search_results_multi" x) switch (status & 0x7f) { case GG_STATUS_AVAIL: case GG_STATUS_AVAIL_DESCR: active = format_string(format_find(__format("_active")), (__firstname) ? __firstname : nickname); break; case GG_STATUS_BUSY: case GG_STATUS_BUSY_DESCR: active = format_string(format_find(__format("_busy")), (__firstname) ? __firstname : nickname); break; case GG_STATUS_DND: case GG_STATUS_DND_DESCR: active = format_string(format_find(__format("_dnd")), (__firstname) ? __firstname : nickname); break; case GG_STATUS_FFC: case GG_STATUS_FFC_DESCR: active = format_string(format_find(__format("_ffc")), (__firstname) ? __firstname : nickname); break; case GG_STATUS_INVISIBLE: case GG_STATUS_INVISIBLE_DESCR: active = format_string(format_find(__format("_invisible")), (__firstname) ? __firstname : nickname); break; default: active = format_string(format_find(__format("_inactive")), (__firstname) ? __firstname : nickname); } gender = format_string(format_find(__format("_unknown")), ""); for (l = autofinds; l; l = l->next) { uin_t *d = l->data; if (*d == atoi(uin)) { target = uin; break; } } print_window(target, 0, __format(""), uin, name, nickname, city, birthyear, gender, active); #undef __format xfree(name); xfree(active); xfree(gender); xfree(firstname); xfree(lastname); xfree(nickname); xfree(city); last_uin = atoi(uin); } /* jeśli mieliśmy ,,/find --all'', szukamy dalej */ for (l = searches; l; l = l->next) { gg_pubdir50_t req = l->data; uin_t next; if (gg_pubdir50_seq(req) != gg_pubdir50_seq(res)) continue; /* nie ma dalszych? to dziękujemy */ if (!(next = gg_pubdir50_next(res)) || !sess || next < last_uin) { list_remove(&searches, req, 0); gg_pubdir50_free(req); break; } gg_pubdir50_add(req, GG_PUBDIR50_START, itoa(next)); gg_pubdir50(sess, req); break; } } /* * handle_change50() * * zajmuje się obsługą zmiany danych w katalogu publicznym. * * - e - opis zdarzenia */ void handle_change50(struct gg_event *e) { if (!change_quiet) print("change"); } /* * handle_image_request() * * obsługuje żądanie wysłania obrazków. * * - e - opis zdarzenia */ void handle_image_request(struct gg_event *e) { gg_debug(GG_DEBUG_MISC, "// ekg: image_request: sender=%d, size=%d, crc32=%.8x\n", e->event.image_request.sender, e->event.image_request.size, e->event.image_request.crc32); } /* * handle_image_reply() * * obsługuje odpowiedź obrazków. * * - e - opis zdarzenia */ void handle_image_reply(struct gg_event *e) { struct userlist *u; list_t l; gg_debug(GG_DEBUG_MISC, "// ekg: image_reply: sender=%d, filename=\"%s\", size=%d, crc32=%.8x\n", e->event.image_reply.sender, ((e->event.image_reply.filename) ? e->event.image_reply.filename : "NULL"), e->event.image_reply.size, e->event.image_reply.crc32); if (e->event.image_reply.size != 0) { /* to nie jest spy */ if (config_receive_images) { unsigned char *fname, *path, *tmp; int fd; ssize_t rs; fname = xstrdup(e->event.image_reply.filename); fix_filename(fname); cp_to_iso(fname); if (config_dcc_dir) path = saprintf("%s/%s", config_dcc_dir, fname); else path = xstrdup(fname); tmp = unique_name(path); if (!tmp) { print("dcc_get_cant_overwrite", path); goto err; } else if (tmp != path) { print("dcc_get_backup_made", path, tmp); xfree(path); path = tmp; } gg_debug(GG_DEBUG_MISC, "// ekg: trying to save image: %s\n", path); fd = open(path, O_WRONLY | O_CREAT, config_files_mode_received); if (fd == -1) goto err; rs = write(fd, e->event.image_reply.image, e->event.image_reply.size); if (rs == -1) { int xerrno = errno; close(fd); unlink(path); errno = xerrno; goto err; } else if (rs != e->event.image_reply.size) { close(fd); unlink(path); errno = ENOSPC; goto err; } if (fsync(fd) == -1) { int xerrno = errno; close(fd); unlink(path); errno = xerrno; goto err; } if (close(fd) == -1) { int xerrno = errno; unlink(path); errno = xerrno; goto err; } print("image_saved", format_user(e->event.image_reply.sender), path); xfree(path); event_check(EVENT_IMAGE, e->event.image_reply.sender, fname); xfree(fname); return; err: print("image_not_saved", format_user(e->event.image_reply.sender), path, strerror(errno)); xfree(path); xfree(fname); return; } return; } u = userlist_find(e->event.image_reply.sender, NULL); if (u) { for (l = spiedlist; l; l = l->next) { struct spied *s = l->data; if (s->uin == u->uin) { int sec; int msec; struct timeval now; gettimeofday(&now, NULL); if (now.tv_usec < s->request_sent.tv_usec) { sec = now.tv_sec - s->request_sent.tv_sec - 1; msec = (now.tv_usec - s->request_sent.tv_usec + 1000000) / 1000; } else { sec = now.tv_sec - s->request_sent.tv_sec; msec = (now.tv_usec - s->request_sent.tv_usec) / 1000; } gg_debug(GG_DEBUG_MISC, "// ekg: image_reply: round-trip-time %d.%03d\n", sec, msec); list_remove(&spiedlist, s, 1); break; } } } /* * odpowiedź prawdopodobnie zakolejkowana przez serwer, upewnijmy się że dana osoba * rzeczywiście w tej chwili się ukrywa. */ if (e->event.image_reply.crc32 + SPYING_RESPONSE_TIMEOUT < time(NULL)) { gg_debug(GG_DEBUG_MISC, "// ekg: spying image reply too old for %d, checking again\n", e->event.image_reply.sender); check_conn(e->event.image_reply.sender); return; } if (u && group_member(u, "spied")) { if (GG_S_NA(u->status)) { int status = (GG_S_D(u->status)) ? GG_STATUS_INVISIBLE_DESCR : GG_STATUS_INVISIBLE; iso_to_cp(u->descr); handle_common(u->uin, status, u->descr, time(NULL), u->ip.s_addr, u->port, u->protocol, u->image_size); } } else { if (u) print("user_is_connected", format_user(e->event.image_reply.sender), (u->first_name) ? u->first_name : u->display); else print("user_is_connected", format_user(e->event.image_reply.sender), itoa(e->event.image_reply.sender)); } } /* * handle_dcc7_new() * * obsługuje nowe połączenie dcc. * * - e - opis zdarzenia */ void handle_dcc7_new(struct gg_event *e) { struct gg_dcc7 *dcc = e->event.dcc7_new; struct transfer t; if (!config_dcc) { gg_dcc7_reject(dcc, GG_DCC7_REJECT_USER); gg_dcc7_free(dcc); e->event.dcc7_new = NULL; return; } if (check_dcc_limit(e) == -1) return; memset(&t, 0, sizeof(t)); t.id = transfer_id(); t.uin = dcc->peer_uin; t.dcc7 = dcc; switch (dcc->dcc_type) { case GG_DCC7_TYPE_FILE: { struct stat st; char *path; t.type = GG_SESSION_DCC7_GET; t.filename = xstrdup(dcc->filename); cp_to_iso(t.filename); fix_filename(t.filename); print("dcc_get_offer", format_user(t.uin), t.filename, itoa(dcc->size), itoa(t.id)); if (config_dcc_dir) path = saprintf("%s/%s", config_dcc_dir, t.filename); else path = xstrdup(t.filename); if (!stat(path, &st) && st.st_size < dcc->size) print("dcc_get_offer_resume", format_user(t.uin), t.filename, itoa(dcc->size), itoa(t.id)); xfree(path); break; } case GG_DCC7_TYPE_VOICE: #ifdef HAVE_VOIP t.type = GG_SESSION_DCC7_VOICE; print("dcc_voice_offer", format_user(t.uin), itoa(t.id)); break; #else gg_dcc7_reject(dcc, GG_DCC7_REJECT_USER); gg_dcc7_free(dcc); e->event.dcc7_new = NULL; return; #endif default: gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_dcc7_new() unknown type %d\n", dcc->type); } list_add(&transfers, &t, sizeof(t)); if (!(ignored_check(t.uin) & IGNORE_EVENTS)) event_check(EVENT_DCC, t.uin, t.filename); } /* * handle_dcc7_accept() * * obsługuje akceptację połączenia dcc. * * - e - opis zdarzenia */ void handle_dcc7_accept(struct gg_event *e) { } /* * handle_dcc7_reject() * * obsługuje odrzucenie połączenia dcc. * * - e - opis zdarzenia */ void handle_dcc7_reject(struct gg_event *e) { struct gg_dcc7 *d = e->event.dcc7_accept.dcc7; print("dcc_error_refused", format_user(d->peer_uin)); #ifdef HAVE_VOIP if (d->type == GG_SESSION_DCC7_VOICE) voice_close(); #endif /* HAVE_VOIP */ remove_transfer(d); list_remove(&watches, d, 0); gg_dcc7_free(d); } ekg-1.9~pre+r2855/src/events.h000066400000000000000000000027731174410337000160740ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * Dawid Jarosz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __EVENTS_H #define __EVENTS_H #include "libgadu.h" #include "userlist.h" struct handler { int type; void (*handler)(struct gg_event *e); }; void handle_event(struct gg_session *s); void handle_dcc(struct gg_dcc *s); void handle_dcc7(struct gg_dcc7 *s); void handle_msg(struct gg_event *e); void handle_voice(struct gg_common *c); void handle_pubdir(struct gg_http *s); void handle_token(struct gg_http *s); void handle_disconnect(struct gg_event *e); void print_message(struct gg_event *e, struct userlist *u, int chat, int secure); void remove_transfer(void *d); void handle_common(uin_t uin, int status, const char *idescr, int dtime, uint32_t ip, uint16_t port, int version, int image_size); #endif /* __EVENTS_H */ ekg-1.9~pre+r2855/src/ioctld.c000066400000000000000000000133401174410337000160310ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2004 Paweł Maziarz * Wojtek Kaniewski * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) # include #endif #ifdef sun /* Solaris */ # include # include #endif #ifdef __linux__ # include # include #endif #include #include #include #include #include #include #include #include #include "ioctld.h" #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif char sock_path[PATH_MAX + 1] = ""; int blink_leds(int *flag, int *delay) { int s, fd, restore_data; #ifdef sun if ((fd = open("/dev/kbd", O_RDONLY)) == -1) return -1; ioctl(fd, KIOCGLED, &restore_data); #else if ((fd = open("/dev/console", O_WRONLY)) == -1) fd = STDOUT_FILENO; ioctl(fd, KDGETLED, &restore_data); #endif for (s = 0; flag[s] >= 0 && s < IOCTLD_MAX_ITEMS; s++) { #ifdef sun int leds = 0; /* tak.. na sunach jest to troszkę inaczej */ if (flag[s] & 1) leds |= LED_NUM_LOCK; if (flag[s] & 2) leds |= LED_SCROLL_LOCK; if (flag[s] & 4) leds |= LED_CAPS_LOCK; ioctl(fd, KIOCSLED, &leds); #else ioctl(fd, KDSETLED, flag[s]); #endif if (delay[s]) { if (delay[s] <= IOCTLD_MAX_DELAY) usleep(delay[s]); else usleep(IOCTLD_MAX_DELAY); } } #ifdef sun ioctl(fd, KIOCSLED, &restore_data); #else ioctl(fd, KDSETLED, restore_data); #endif if (fd != STDOUT_FILENO) close(fd); return 0; } int beeps_spk(int *tone, int *delay) { int s; #ifndef sun int fd; if ((fd = open("/dev/console", O_WRONLY)) == -1) fd = STDOUT_FILENO; #endif for (s = 0; tone[s] >= 0 && s < IOCTLD_MAX_ITEMS; s++) { #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) ioctl(fd, KIOCSOUND, 0); #endif #ifndef sun ioctl(fd, KIOCSOUND, tone[s]); #else /* żałosna namiastka... */ putchar('\a'); fflush(stdout); #endif if (delay[s]) { if (delay[s] <= IOCTLD_MAX_DELAY) usleep(delay[s]); else usleep(IOCTLD_MAX_DELAY); } } #ifndef sun ioctl(fd, KIOCSOUND, 0); if (fd != STDOUT_FILENO) close(fd); #endif return 0; } void quit() { unlink(sock_path); exit(0); } int main(int argc, char **argv) { int sock, netsock = -1, rsock = -1, netport = 0, i, on = 1; socklen_t size, length; struct sockaddr_un addr; struct sockaddr_in netaddr, rnetaddr; struct action_data data; if (argc != 2 && argc != 3) { printf("program ten nie jest przeznaczony do samodzielnego wykonywania!\n"); exit(1); } if (strlcpy(sock_path, argv[1], sizeof(sock_path)) >= sizeof(sock_path)) exit(1); addr.sun_family = AF_UNIX; if (strlcpy(addr.sun_path, sock_path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) exit(1); length = sizeof(addr); if (argv[2]) { netport = atoi(argv[2]); if (netport < 1024 || netport > 65535) exit(1); /* niepotrzebne nam niepotrzebne uprawnienia ;) */ setuid(getuid()); } signal(SIGQUIT, quit); signal(SIGTERM, quit); signal(SIGINT, quit); signal(SIGHUP, quit); umask(0177); close(STDERR_FILENO); unlink(sock_path); if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) exit(1); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) exit(2); chown(sock_path, getuid(), -1); if (netport) { /* network stuff */ if ((netsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { unlink(sock_path); exit(3); } /* czasem sie moze przydac */ setsockopt(netsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); netaddr.sin_family = AF_INET; netaddr.sin_port = htons(netport); netaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* nie rezygnujmy od razu */ for (i = 180; i; i--) { if (bind(netsock, (struct sockaddr *)&netaddr, sizeof(struct sockaddr_in))) break; sleep(1); } if (i == 0) { unlink(sock_path); close(netsock); exit(4); } size = sizeof(netaddr); if (listen(netsock, 1) == -1) { unlink(sock_path); close(netsock); exit(4); } netaccept: if ((rsock = accept(netsock, (struct sockaddr *)&rnetaddr, &size)) == -1) { if (errno == ECONNABORTED) goto netaccept; else { unlink(sock_path); close(netsock); exit(4); } } } /* czytamy z lokalnego socketa... */ while (1) { if (recvfrom(sock, &data, sizeof(data), 0, (struct sockaddr *)&addr, &length) == -1) continue; if (netport) { if (write(rsock, &data, sizeof(data)) <= 0) goto netaccept; } else { if (data.act == ACT_BLINK_LEDS) blink_leds(data.value, data.delay); else if (data.act == ACT_BEEPS_SPK) beeps_spk(data.value, data.delay); } } if (netport) close(netsock); unlink(sock_path); exit(0); } ekg-1.9~pre+r2855/src/ioctld.h000066400000000000000000000022531174410337000160370ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002 Pawel Maziarz * Wojtek Kaniewski * Robert J. Wozny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __IOCTLD_H #define __IOCTLD_H #define IOCTLD_MAX_ITEMS 50 #define IOCTLD_MAX_DELAY 2000000 #define IOCTLD_DEFAULT_DELAY 100000 struct action_data { int act; int value[IOCTLD_MAX_ITEMS]; int delay[IOCTLD_MAX_ITEMS]; }; enum action_type { ACT_BLINK_LEDS = 1, ACT_BEEPS_SPK = 2 }; int blink_leds(int *flag, int *delay); int beeps_spk(int *tone, int *delay); #endif /* __IOCTLD_H */ ekg-1.9~pre+r2855/src/log.c000066400000000000000000000177511174410337000153460ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include "log.h" #ifdef HAVE_ZLIB_H # include #endif #include "dynstuff.h" #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "xmalloc.h" #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif list_t lasts = NULL; int config_last_size = 10; int config_last = 0; int config_log = 0; int config_log_ignored = 0; int config_log_status = 0; char *config_log_path = NULL; char *config_log_timestamp = NULL; /* * last_add() * * dodaje wiadomość do listy ostatnio otrzymanych. * * - type - rodzaj wiadomości, * - uin - nadawca, * - t - czas, * - st - czas nadania, * - msg - treść wiadomości. */ void last_add(int type, uin_t uin, time_t t, time_t st, const char *msg) { list_t l; struct last ll; int count = 0; /* nic nie zapisujemy, jeżeli user sam nie wie czego chce. */ if (config_last_size <= 0) return; if (config_last & 2) count = last_count(uin); else count = list_count(lasts); /* usuwamy ostatnią wiadomość, w razie potrzeby... */ if (count >= config_last_size) { time_t tmp_time = 0; /* najpierw ją znajdziemy... */ for (l = lasts; l; l = l->next) { struct last *lll = l->data; if (config_last & 2 && lll->uin != uin) continue; if (!tmp_time) tmp_time = lll->time; if (lll->time <= tmp_time) tmp_time = lll->time; } /* ...by teraz usunąć */ for (l = lasts; l; l = l->next) { struct last *lll = l->data; if (lll->time == tmp_time && lll->uin == uin) { xfree(lll->message); list_remove(&lasts, lll, 1); break; } } } ll.type = type; ll.uin = uin; ll.time = t; ll.sent_time = st; ll.message = (unsigned char *) xstrdup(msg); list_add(&lasts, &ll, sizeof(ll)); return; } /* * last_del() * * usuwa wiadomości skojarzone z daną osobą. * * - uin - numerek osoby. */ void last_del(uin_t uin) { list_t l; for (l = lasts; l; ) { struct last *ll = l->data; l = l->next; if (uin == ll->uin) { xfree(ll->message); list_remove(&lasts, ll, 1); } } } /* * last_count() * * zwraca ilość wiadomości w last dla danej osoby. * * - uin. */ int last_count(uin_t uin) { int count = 0; list_t l; for (l = lasts; l; l = l->next) { struct last *ll = l->data; if (uin == ll->uin) count++; } return count; } /* * last_free() * * zwalnia miejsce po last. */ void last_free() { list_t l; if (!lasts) return; for (l = lasts; l; l = l->next) { struct last *ll = l->data; xfree(ll->message); } list_destroy(lasts, 1); lasts = NULL; } /* * log_escape() * * jeśli trzeba, eskejpuje tekst do logów. * * - str - tekst. * * zaalokowany bufor. */ static char *log_escape(const char *str) { const char *p; char *res, *q; int size, needto = 0; if (!str) return NULL; for (p = str; *p; p++) { if (*p == '"' || *p == '\'' || *p == '\r' || *p == '\n' || *p == ',') needto = 1; } if (!needto) return xstrdup(str); for (p = str, size = 0; *p; p++) { if (*p == '"' || *p == '\'' || *p == '\r' || *p == '\n' || *p == '\\') size += 2; else size++; } q = res = xmalloc(size + 3); *q++ = '"'; for (p = str; *p; p++, q++) { if (*p == '\\' || *p == '"' || *p == '\'') { *q++ = '\\'; *q = *p; } else if (*p == '\n') { *q++ = '\\'; *q = 'n'; } else if (*p == '\r') { *q++ = '\\'; *q = 'r'; } else *q = *p; } *q++ = '"'; *q = 0; return res; } /* * put_log() * * wrzuca do logów informację od/do danego numerka. podaje się go z tego * względu, że gdy `log = 2', informacje lecą do $config_log_path/$uin. * automatycznie eskejpuje, co trzeba. * * - uin - numer delikwenta, * - format... - akceptuje tylko %s, %d i %ld. */ void put_log(uin_t uin, const char *format, ...) { char *lp = config_log_path; char path[PATH_MAX + 1], *buf; const char *p; size_t size = 0; va_list ap; FILE *f; if (!config_log) return; /* oblicz długość tekstu */ va_start(ap, format); for (p = format; *p; p++) { int long_int = 0; if (*p == '%') { p++; if (!*p) break; if (*p == 'l') { p++; long_int = 1; if (!*p) break; } if (*p == 's') { char *e, *tmp = va_arg(ap, char*); e = log_escape(tmp); size += strlen(e); xfree(e); } if (*p == 'd') { int tmp = ((long_int) ? va_arg(ap, long) : va_arg(ap, int)); size += strlen(itoa(tmp)); } } else size++; } va_end(ap); /* zaalokuj bufor */ buf = xmalloc(size + 1); *buf = 0; /* utwórz tekst z logiem */ va_start(ap, format); for (p = format; *p; p++) { int long_int = 0; if (*p == '%') { p++; if (!*p) break; if (*p == 'l') { p++; long_int = 1; if (!*p) break; } if (*p == 's') { char *e, *tmp = va_arg(ap, char*); e = log_escape(tmp); strlcat(buf, e, size + 1); xfree(e); } if (*p == 'd') { int tmp = ((long_int) ? va_arg(ap, long) : va_arg(ap, int)); strlcat(buf, itoa(tmp), size + 1); } } else { buf[strlen(buf) + 1] = 0; buf[strlen(buf)] = *p; } } /* teraz skonstruuj ścieżkę logów */ if (!lp) lp = (config_log & 2) ? (char *) prepare_path("", 0) : (char *) prepare_path("history", 0); if (*lp == '~') snprintf(path, sizeof(path), "%s%s", home_dir, lp + 1); else strlcpy(path, lp, sizeof(path)); if ((config_log & 2)) { if (mkdir(path, 0700) && errno != EEXIST) goto cleanup; if (uin) snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%u", uin); else snprintf(path + strlen(path), sizeof(path) - strlen(path), "/sms"); } #ifdef HAVE_ZLIB /* nawet jeśli chcemy gzipowane logi, a istnieje nieskompresowany log, * olewamy kompresję. jeśli loga nieskompresowanego nie ma, dodajemy * rozszerzenie .gz i balujemy. */ if (config_log & 4) { struct stat st; if (stat(path, &st) == -1) { gzFile f; snprintf(path + strlen(path), sizeof(path) - strlen(path), ".gz"); if (!(f = gzopen(path, "a"))) goto fail; if (gzputs(f, buf) == -1) { gzclose(f); goto fail; } if (gzclose(f) != Z_OK) goto fail; chmod(path, config_files_mode_config); goto cleanup; } } #endif if (!(f = fopen(path, "a"))) goto fail; fputs(buf, f); if (fclose(f) != 0) goto fail; chmod(path, config_files_mode_config); cleanup: xfree(buf); return; fail: xfree(buf); print("log_failed", strerror(errno)); return; } /* * log_timestamp() * * zwraca timestamp logów zgodnie z życzeniem użytkownika. * * - t - czas, który mamy zamienić. * * zwraca na przemian jeden z dwóch statycznych buforów, więc w obrębie * jednego wyrażenia można wywołać tę funkcję dwukrotnie. */ const char *log_timestamp(time_t t) { static char buf[2][100]; struct tm *tm = localtime(&t); static int i = 0; i = i % 2; if (config_log_timestamp) { strftime(buf[i], sizeof(buf[0]), config_log_timestamp, tm); return buf[i++]; } else return itoa(t); } ekg-1.9~pre+r2855/src/log.h000066400000000000000000000031271174410337000153430ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __LOG_H #define __LOG_H #include #include #include "dynstuff.h" #include "libgadu.h" struct last { int type; /* 0 - przychodząca, 1 - wychodząca */ uin_t uin; /* od kogo, lub do kogo przy wysyłanych */ time_t time; /* czas */ time_t sent_time; /* czas wysłania wiadomości przychodzącej */ unsigned char *message; /* wiadomość */ }; list_t lasts; void last_add(int type, uin_t uin, time_t t, time_t st, const char *msg); void last_del(uin_t uin); int last_count(uin_t uin); void last_free(void); void put_log(uin_t uin, const char *format, ...); const char *log_timestamp(time_t t); #endif /* __LOG_H */ ekg-1.9~pre+r2855/src/mail.c000066400000000000000000000221201174410337000154710ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2004 Piotr Domagalski * Paweł Maziarz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_UTIMES # include #endif #include "configfile.h" #include "dynstuff.h" #include "mail.h" #include "stuff.h" #include "themes.h" #include "ui.h" #include "xmalloc.h" list_t mail_folders = NULL; int config_check_mail = 0; int config_check_mail_frequency = 15; char *config_check_mail_folders = NULL; int mail_count = 0; int last_mail_count = 0; /* * check_mail() * * wywołuje odpowiednie sprawdzanie poczty. */ void check_mail() { if (!config_check_mail) return; if (config_check_mail & 1) check_mail_mbox(); else if (config_check_mail & 2) check_mail_maildir(); } /* * check_mail_update() * * modyfikuje liczbę nowych emaili i daje o tym znać. * * 0/-1 */ int check_mail_update(const char *s, int more) { int h = 0, c = 0, new_count = 0; char **buf = NULL; list_t l; if (!s) return -1; buf = array_make(s, ",", 0, 0, 0); if (array_count(buf) != 2) { array_free(buf); return -1; } h = atoi(buf[0]); c = atoi(buf[1]); array_free(buf); for (l = mail_folders; l; l = l->next) { struct mail_folder *m = l->data; if (m->fhash == h) m->count = c; new_count += m->count; } if (new_count == mail_count) return 0; if (!more) { last_mail_count = mail_count; mail_count = new_count; } if (!more && mail_count && mail_count > last_mail_count) { if (config_check_mail & 4) { if (mail_count == 1) print("new_mail_one"); else { if (mail_count >= 2 && mail_count <= 4) print("new_mail_two_four", itoa(mail_count)); else print("new_mail_more", itoa(mail_count)); } } if (config_beep && config_beep_mail) ui_beep(); play_sound(config_sound_mail_file); event_check(EVENT_NEWMAIL, 0, itoa(mail_count)); } return 0; } /* * check_mail_mbox() * * tworzy dzieciaka, który sprawdza wszystkie pliki typu * mbox i liczy, ile jest nowych wiadomości, potem zwraca * wynik rurką. sprawdza tylko te pliki, które były * modyfikowane od czasu ostatniego sprawdzania. * * 0/-1 */ int check_mail_mbox() { int fd[2], pid, to_check = 0; struct gg_exec x; list_t l; for (l = mail_folders; l; l = l->next) { struct mail_folder *m = l->data; struct stat st; /* plik mógł zostać usunięty, uaktualnijmy */ if (stat(m->fname, &st)) { if (m->count) { char *buf = saprintf("%d,%d", m->fhash, 0); check_mail_update(buf, 0); xfree(buf); } m->mtime = 0; m->size = 0; m->check = 0; m->count = 0; continue; } if ((st.st_mtime != m->mtime) || (st.st_size != m->size)) { m->mtime = st.st_mtime; m->size = st.st_size; m->check = 1; to_check++; } else m->check = 0; } if (!to_check || pipe(fd)) return -1; if ((pid = fork()) < 0) { close(fd[0]); close(fd[1]); return -1; } if (!pid) { /* born to be wild */ char *s = NULL, *line = NULL; int f_new = 0, new = 0, in_header = 0, i = 0; FILE *f; struct stat st; close(fd[0]); for (l = mail_folders; l; l = l->next) { struct mail_folder *m = l->data; if (!m->check) continue; i++; if (stat(m->fname, &st) || !(f = fopen(m->fname, "r"))) continue; while ((line = read_file(f))) { char *line_save = line; if (!strncmp(line, "From ", 5)) { in_header = 1; f_new++; } if (in_header && (!strncmp(line, "Status: RO", 10) || !strncmp(line, "Status: O", 9))) f_new--; strip_spaces(line); if (strlen(line) == 0) in_header = 0; xfree(line_save); } fclose(f); #ifdef HAVE_UTIMES { struct timeval foo[2]; foo[0].tv_sec = st.st_atime; foo[1].tv_sec = st.st_mtime; utimes(m->fname, foo); } #else { struct utimbuf foo; foo.actime = st.st_atime; foo.modtime = st.st_mtime; utime(m->fname, &foo); } #endif if (i == to_check) s = saprintf("%d,%d", m->fhash, f_new); else s = saprintf("%d,%d\n", m->fhash, f_new); write(fd[1], s, strlen(s)); xfree(s); new += f_new; f_new = 0; } close(fd[1]); exit(0); } memset(&x, 0, sizeof(x)); x.fd = fd[0]; x.check = GG_CHECK_READ; x.state = GG_STATE_READING_DATA; x.type = GG_SESSION_USER4; x.id = pid; x.timeout = 60; x.buf = string_init(NULL); fcntl(x.fd, F_SETFL, O_NONBLOCK); list_add(&watches, &x, sizeof(x)); process_add(pid, "\003"); close(fd[1]); return 0; } /* * check_mail_maildir() * * tworzy dzieciaka, który sprawdza wszystkie * katalogi typu Maildir i liczy, ile jest w nich * nowych wiadomości. zwraca wynik rurką. * * 0/-1 */ int check_mail_maildir() { int fd[2], pid; struct gg_exec x; if (pipe(fd)) return -1; if ((pid = fork()) < 0) { close(fd[0]); close(fd[1]); return -1; } if (!pid) { /* born to be wild */ int d_new = 0, new = 0; char *s = NULL; struct dirent *d; DIR *dir; list_t l; close(fd[0]); for (l = mail_folders; l; l = l->next) { struct mail_folder *m = l->data; char *tmp = saprintf("%s/new", m->fname); if ((dir = opendir(tmp)) != NULL) { while ((d = readdir(dir))) { char *fname = saprintf("%s/%s", tmp, d->d_name); struct stat st; if (d->d_name[0] != '.' && !stat(fname, &st) && S_ISREG(st.st_mode)) d_new++; xfree(fname); } closedir(dir); } else d_new = 0; xfree(tmp); if (l->next) s = saprintf("%d,%d\n", m->fhash, d_new); else s = saprintf("%d,%d", m->fhash, d_new); write(fd[1], s, strlen(s)); xfree(s); new += d_new; d_new = 0; } close(fd[1]); exit(0); } memset(&x, 0, sizeof(x)); x.fd = fd[0]; x.check = GG_CHECK_READ; x.state = GG_STATE_READING_DATA; x.type = GG_SESSION_USER4; x.id = pid; x.timeout = 60; x.buf = string_init(NULL); fcntl(x.fd, F_SETFL, O_NONBLOCK); list_add(&watches, &x, sizeof(x)); process_add(pid, "\003"); close(fd[1]); return 0; } /* * changed_check_mail() * * wywoływane przy zmianie zmiennej ,,check_mail''. */ void changed_check_mail(const char *var) { if (config_check_mail) { list_t l; /* konieczne, jeśli była zmiana typu skrzynek */ changed_check_mail_folders("check_mail_folders"); for (l = timers; l; l = l->next) { struct timer *t = l->data; if (t->type == TIMER_UI && !strcmp(t->name, "check-mail-time")) { t->period = config_check_mail_frequency; return; } } /* brzydki hack, żeby się nikt nie czepiał */ if (in_autoexec) { char *tmp = config_read_variable("check_mail_frequency"); if (tmp) { config_check_mail_frequency = atoi(tmp); xfree(tmp); } } if (config_check_mail_frequency) timer_add(config_check_mail_frequency, 1, TIMER_UI, 0, "check-mail-time", "check_mail"); } else timer_remove("check-mail-time", 0, NULL); } /* * changed_check_mail_folders() * * wywoływane przy zmianie ,,check_mail_folders''. */ void changed_check_mail_folders(const char *var) { struct mail_folder foo; check_mail_free(); memset(&foo, 0, sizeof(foo)); if (config_check_mail & 1) { char *inbox = xstrdup(getenv("MAIL")); if (!inbox) { struct passwd *pw = getpwuid(getuid()); if (!pw) return; inbox = saprintf("/var/mail/%s", pw->pw_name); } foo.fhash = ekg_hash(inbox); foo.fname = inbox; foo.check = 1; list_add(&mail_folders, &foo, sizeof(foo)); } else { if (config_check_mail & 2) { char *inbox = saprintf("%s/Maildir", home_dir); foo.fhash = ekg_hash(inbox); foo.fname = inbox; foo.check = 1; list_add(&mail_folders, &foo, sizeof(foo)); } } if (config_check_mail_folders) { char **f = NULL; int i; f = array_make(config_check_mail_folders, ", ", 0, 1, 1); for (i = 0; f[i]; i++) { if (f[i][0] != '/') { char *buf = saprintf("%s/%s", home_dir, f[i]); xfree(f[i]); f[i] = buf; } foo.fhash = ekg_hash(f[i]); foo.fname = f[i]; foo.check = 1; list_add(&mail_folders, &foo, sizeof(foo)); } xfree(f); } } /* * check_mail_free() * * zwalnia pamięć po liście folderów z pocztą. */ void check_mail_free() { list_t l; if (!mail_folders) return; for (l = mail_folders; l; l = l->next) { struct mail_folder *m = l->data; xfree(m->fname); } list_destroy(mail_folders, 1); mail_folders = NULL; } ekg-1.9~pre+r2855/src/mail.h000066400000000000000000000023611174410337000155030ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Piotr Domagalski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __MAIL_H #define __MAIL_H #include #include #include "dynstuff.h" struct mail_folder { int fhash; char *fname; time_t mtime; off_t size; int count; int check; }; list_t mail_folders; int mail_count; int last_mail_count; void check_mail(void); int check_mail_mbox(void); int check_mail_maildir(void); int check_mail_update(const char *s, int more); void check_mail_free(void); void changed_check_mail(const char *var); void changed_check_mail_folders(const char *var); #endif /* __MAIL_H */ ekg-1.9~pre+r2855/src/msgqueue.c000066400000000000000000000173721174410337000164170ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Piotr Domagalski * Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "dynstuff.h" #include "libgadu.h" #include "msgqueue.h" #include "stuff.h" #include "xmalloc.h" list_t msg_queue = NULL; /* * find_in_uins() * * sprawdza, czy w ciągu uin'ów znajduje się dany uin. * * 1 jeśli znaleziono, 0 jeśli nie. */ int find_in_uins(int uin_count, uin_t *uins, uin_t uin) { int i; for (i = 0; i < uin_count; i++) if (uins[i] == uin) return 1; return 0; } /* * msg_queue_add() * * dodaje wiadomość do kolejki wiadomości. * * - msg_class - typ wiadomości, * - msg_seq - numer sekwencyjny, * - uin_count - ilość adresatów, * - uins - adresaci wiadomości, * - msg - wiadomość, * - secure - czy ma być zaszyfrowana, * - format - formatowanie wiadomości, * - formatlen - długość informacji o formatowaniu. * * 0/-1 */ int msg_queue_add(int msg_class, int msg_seq, int uin_count, uin_t *uins, const unsigned char *msg, int secure, const unsigned char *format, int formatlen) { struct msg_queue m; if (uin_count == 1 && uins[0] == config_uin) /* nie dostaniemy potwierdzenia, jeśli wyślemy wiadomość do siebie */ return -1; m.msg_class = msg_class; m.msg_seq = msg_seq; m.uin_count = uin_count; m.uins = xmalloc(uin_count * sizeof(uin_t)); memmove(m.uins, uins, uin_count * sizeof(uin_t)); m.msg = (unsigned char *) xstrdup((const char *) msg); m.secure = secure; m.time = time(NULL); m.formatlen = formatlen; if (formatlen > 0) { m.format = xmalloc(formatlen * sizeof(unsigned char)); memmove(m.format, format, formatlen * sizeof(unsigned char)); } else m.format = NULL; return (list_add(&msg_queue, &m, sizeof(m)) ? 0 : -1); } /* * msg_queue_remove() * * usuwa wiadomość z kolejki wiadomości. * * - msg_seq - numer sekwencyjny wiadomości. * * 0 jeśli usunięto, -1 jeśli nie ma takiej wiadomości. */ int msg_queue_remove(int msg_seq) { list_t l; for (l = msg_queue; l; l = l->next) { struct msg_queue *m = l->data; if (m->msg_seq == msg_seq) { xfree(m->uins); xfree(m->msg); xfree(m->format); list_remove(&msg_queue, m, 1); return 0; } } return -1; } /* * msg_queue_remove_uin() * * usuwa wiadomość z kolejki wiadomości dla danego * użytkownika. * * - uin. * * 0 jeśli usunięto, -1 jeśli nie ma takiej wiadomości. */ int msg_queue_remove_uin(uin_t uin) { list_t l; int x = -1; for (l = msg_queue; l; ) { struct msg_queue *m = l->data; l = l->next; if (find_in_uins(m->uin_count, m->uins, uin)) { xfree(m->uins); xfree(m->msg); xfree(m->format); list_remove(&msg_queue, m, 1); x = 0; } } return x; } /* * msg_queue_free() * * zwalnia pamięć po kolejce wiadomości. */ void msg_queue_free() { list_t l; for (l = msg_queue; l; l = l->next) { struct msg_queue *m = l->data; xfree(m->uins); xfree(m->msg); xfree(m->format); } list_destroy(msg_queue, 1); msg_queue = NULL; } /* * msg_queue_flush() * * wysyła wiadomości z kolejki. * * 0 jeśli wysłano, -1 jeśli nastąpił błąd przy wysyłaniu, -2 jeśli * kolejka pusta. */ int msg_queue_flush() { list_t l = msg_queue; if (!l) return -2; for (; l; l = l->next) { struct msg_queue *m = l->data; int new_seq; unsigned char *tmp = (unsigned char *) xstrdup((const char *) m->msg); iso_to_cp(tmp); if (m->uin_count == 1) { if (m->secure) msg_encrypt(m->uins[0], &tmp); new_seq = gg_send_message_richtext(sess, m->msg_class, m->uins[0], tmp, m->format, m->formatlen); } else new_seq = gg_send_message_confer_richtext(sess, m->msg_class, m->uin_count, m->uins, tmp, m->format, m->formatlen); xfree(tmp); if (new_seq != -1) m->msg_seq = new_seq; else return -1; } return 0; } /* * msg_queue_count() * * zwraca liczbę wiadomości w kolejce. */ int msg_queue_count() { return list_count(msg_queue); } /* * msg_queue_count_uin() * * zwraca liczbę wiadomości w kolejce dla danego * użytkownika. * * - uin. */ int msg_queue_count_uin(uin_t uin) { list_t l; int count = 0; for (l = msg_queue; l; l = l->next) { struct msg_queue *m = l->data; if (find_in_uins(m->uin_count, m->uins, uin)) count++; } return count; } /* * msg_queue_write() * * zapisuje niedostarczone wiadomości na dysku. * * 0/-1 */ int msg_queue_write() { const char *path; list_t l; int num = 0; if (!msg_queue) return -1; path = prepare_path("queue", 1); if (mkdir(path, 0700) && errno != EEXIST) return -1; for (l = msg_queue; l; l = l->next) { struct msg_queue *m = l->data; char *fn; FILE *f; int i; /* nie zapisujemy wiadomości, które załapały się do wysyłki */ if (m->msg_seq != -1) continue; fn = saprintf("%s/%ld.%d", path, (long) m->time, num++); if (!(f = fopen(fn, "w"))) { xfree(fn); continue; } fprintf(f, "%d\n%d\n%d\n", m->msg_class, m->msg_seq, m->uin_count); for (i = 0; i < m->uin_count; i++) fprintf(f, "%d\n", m->uins[i]); fprintf(f, "%d\n%ld\n%d\n", m->secure, (long) m->time, m->formatlen); if (m->formatlen) { for (i = 0; i < m->formatlen; i++) fprintf(f, "%c", m->format[i]); fprintf(f, "\n"); } fprintf(f, "%s", m->msg); fclose(f); chmod(fn, config_files_mode_config); xfree(fn); } return 0; } /* * msg_queue_read() * * wczytuje kolejkę niewysłanych wiadomości z dysku. * * 0/-1 */ int msg_queue_read() { const char *path; struct dirent *d; DIR *dir; path = prepare_path("queue", 0); if (!(dir = opendir(path))) return -1; while ((d = readdir(dir))) { struct msg_queue m; struct stat st; string_t msg; char *fn, *buf; FILE *f; int i; fn = saprintf("%s/%s", path, d->d_name); if (stat(fn, &st) || !S_ISREG(st.st_mode)) { xfree(fn); continue; } if (!(f = fopen(fn, "r"))) { xfree(fn); continue; } memset(&m, 0, sizeof(m)); fscanf(f, "%d\n", &m.msg_class); fscanf(f, "%d\n", &m.msg_seq); fscanf(f, "%d\n", &m.uin_count); /* jakiś zdrowy limit */ if (m.uin_count < 1 || m.uin_count > 100) { fclose(f); xfree(fn); continue; } m.uins = xcalloc(m.uin_count, sizeof(uin_t)); for (i = 0; i < m.uin_count; i++) fscanf(f, "%d\n", &m.uins[i]); fscanf(f, "%d\n", &m.secure); fscanf(f, "%ld\n", (long *) &m.time); fscanf(f, "%d\n", &m.formatlen); /* dziwny plik? */ if (!m.time || !m.msg_seq || !m.msg_class) { fclose(f); xfree(fn); xfree(m.uins); continue; } if (m.formatlen) { m.format = xcalloc(m.formatlen, sizeof(unsigned char)); for (i = 0; i < m.formatlen; i++) fscanf(f, "%c", &m.format[i]); fscanf(f, "%*c"); } else m.format = NULL; msg = string_init(NULL); buf = read_file(f); while (buf) { string_append(msg, buf); xfree(buf); buf = read_file(f); if (buf) string_append(msg, "\r\n"); } m.msg = (unsigned char *) msg->str; string_free(msg, 0); fclose(f); list_add(&msg_queue, &m, sizeof(m)); unlink(fn); xfree(fn); } closedir(dir); return 0; } ekg-1.9~pre+r2855/src/msgqueue.h000066400000000000000000000030741174410337000164160ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Piotr Domagalski * Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __MSGQUEUE_H #define __MSGQUEUE_H #include #include #include "dynstuff.h" #include "libgadu.h" struct msg_queue { int msg_class; int msg_seq; int uin_count; uin_t *uins; int secure; time_t time; unsigned char *msg; unsigned char *format; int formatlen; }; list_t msg_queue; int msg_queue_add(int msg_class, int msg_seq, int uin_count, uin_t *uins, const unsigned char *msg, int secure, const unsigned char *format, int formatlen); int msg_queue_remove(int msg_seq); int msg_queue_remove_uin(uin_t uin); void msg_queue_free(void); int msg_queue_flush(void); int msg_queue_count(void); int msg_queue_count_uin(uin_t uin); int msg_queue_read(void); int msg_queue_write(void); int find_in_uins(int uin_count, uin_t *uins, uin_t uin); #endif /* __MSGQUEUE_H */ ekg-1.9~pre+r2855/src/python.c000066400000000000000000000310271174410337000160760ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2003 Wojtek Kaniewski * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include "commands.h" #include "libgadu.h" #include "stuff.h" #include "themes.h" #include "ui.h" #include "vars.h" #include "version.h" #include "xmalloc.h" #include #include "python.h" int python_handle_result = -1; static PyObject* ekg_cmd_connect(PyObject *self, PyObject *args) { ekg_connect(); return Py_BuildValue(""); } static PyObject* ekg_cmd_disconnect(PyObject *self, PyObject *args) { char *reason = NULL, *tmp; if (!PyArg_ParseTuple(args, "|s", &reason)) return NULL; tmp = saprintf("disconnect %s", ((reason) ? reason : "")); command_exec(NULL, tmp, 0); xfree(tmp); return Py_BuildValue(""); } static PyObject* ekg_cmd_printf(PyObject *self, PyObject *pyargs) { char *format = "generic", *args[9]; int i; for (i = 0; i < 9; i++) args[i] = ""; if (!PyArg_ParseTuple(pyargs, "s|sssssssss:printf", &format, &args[0], &args[1], &args[2], &args[3], &args[4], &args[5], &args[6], &args[7], &args[8])) return NULL; print(format, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); return Py_BuildValue(""); } static PyObject* ekg_cmd_command(PyObject *self, PyObject *args) { char *command = NULL; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; command_exec(NULL, command, 0); return Py_BuildValue(""); } static PyObject* ekg_cmd_print_header(PyObject *self, PyObject *args) { char *text = NULL; int x, y; if (!PyArg_ParseTuple(args, "iis", &x, &y, &text)) return NULL; #ifdef WITH_UI_NCURSES if (header) window_printat(header, x, y, text, NULL, COLOR_WHITE, 0, COLOR_BLUE, 1); #endif return Py_BuildValue(""); } static PyObject* ekg_cmd_print_statusbar(PyObject *self, PyObject *args) { char *text = NULL; int x, y; if (!PyArg_ParseTuple(args, "iis", &x, &y, &text)) return NULL; #ifdef WITH_UI_NCURSES window_printat(status, x, y, text, NULL, COLOR_WHITE, 0, COLOR_BLUE, 1); #endif return Py_BuildValue(""); } static PyObject* ekg_cmd_window_printat(PyObject *self, PyObject *args) { char *target = NULL, *text = NULL; int id, x, y; if (PyArg_ParseTuple(args, "siis", &target, &x, &y, &text)) { ui_event("printat", target, 0, x, y, text, NULL); return Py_BuildValue(""); } if (PyArg_ParseTuple(args, "iiis", &id, &x, &y, &text)) { ui_event("printat", NULL, id, x, y, text, NULL); return Py_BuildValue(""); } return NULL; } static PyObject* ekg_cmd_window_commit(PyObject *self, PyObject *args) { ui_event("commit", NULL); return Py_BuildValue(""); } static PyObject* ekg_cmd_window_list(PyObject *self, PyObject *args) { int i, start, stop, *windowlist; PyObject *wynik, *val; if (!PyArg_ParseTuple(args, "ii", &start, &stop)) return NULL; if (start < 1 || start > stop) { PyErr_SetString(PyExc_ValueError, "invalid range"); return NULL; } windowlist = xmalloc((stop - start + 2) * sizeof(int)); ui_event("get_window_list", windowlist, start, stop); wynik = PyList_New(windowlist[0]); for (i = 0; i < windowlist[0]; i++) { val = Py_BuildValue("i", windowlist[i + 1]); PyList_SetItem(wynik, i, val); } xfree(windowlist); return wynik; } static PyMethodDef ekg_methods[] = { { "connect", ekg_cmd_connect, METH_VARARGS, "" }, { "disconnect", ekg_cmd_disconnect, METH_VARARGS, "" }, { "printf", ekg_cmd_printf, METH_VARARGS, "" }, { "command", ekg_cmd_command, METH_VARARGS, "" }, { "print_header", ekg_cmd_print_header, METH_VARARGS, "" }, { "print_statusbar", ekg_cmd_print_statusbar, METH_VARARGS, "" }, { "window_printat", ekg_cmd_window_printat, METH_VARARGS, "" }, { "window_commit", ekg_cmd_window_commit, METH_VARARGS, "" }, { "window_list", ekg_cmd_window_list, METH_VARARGS, "" }, { NULL, NULL, 0, NULL } }; static PyObject *ekg_config_getattr(PyObject *o, char *name) { struct variable *v = variable_find(name); if (!v) { PyErr_SetString(PyExc_LookupError, "unknown variable"); return NULL; } if (v->type == VAR_BOOL || v->type == VAR_INT || v->type == VAR_MAP) return Py_BuildValue("i", *(int*)(v->ptr)); else return Py_BuildValue("s", *(char**)(v->ptr)); } static int ekg_config_setattr(PyObject *o, char *name, PyObject *value) { struct variable *v = variable_find(name); if (!v) { PyErr_SetString(PyExc_LookupError, "unknown variable"); return -1; } if (value == NULL) { PyErr_SetString(PyExc_TypeError, "can't delete config variables"); return -1; } if (v->type == VAR_INT || v->type == VAR_BOOL || v->type == VAR_MAP) { if (!PyInt_Check(value)) { PyErr_SetString(PyExc_TypeError, "invalid type"); return -1; } if (variable_set(name, itoa(PyInt_AsLong(value)), 0)) { PyErr_SetString(PyExc_ValueError, "invalid value"); return -1; } } else { if (!PyString_Check(value)) { PyErr_SetString(PyExc_TypeError, "invalid type"); return -1; } if (variable_set(name, PyString_AsString(value), 0)) { PyErr_SetString(PyExc_ValueError, "invalid value"); return -1; } } return 0; } static void ekg_config_dealloc(PyObject *o) { } static PyTypeObject ekg_config_type = { PyObject_HEAD_INIT(&PyType_Type) 0, "config", sizeof(PyObject), 0, ekg_config_dealloc, 0, ekg_config_getattr, ekg_config_setattr, }; int python_initialize() { PyObject *ekg, *ekg_config; /* PyImport_ImportModule spodziewa się nazwy modułu, który znajduje * się w $PYTHONPATH, więc dodajemy tam katalog ~/.gg/scripts. można * to zrobić w bardziej elegancki sposób, ale po co komplikować sobie * życie? * * Argument putenv() nie jest zwalniany xfree(), bo powoduje to * problemy na systemach, w których putenv() jest zgodne z SUSv2 (np * niektóre SunOS). */ if (getenv("PYTHONPATH")) { char *tmp = saprintf("%s:%s", getenv("PYTHONPATH"), prepare_path("scripts", 0)); #ifdef HAVE_SETENV setenv("PYTHONPATH", tmp, 1); #else { char *s = saprintf("PYTHONPATH=%s", tmp); putenv(s); } #endif xfree(tmp); } else { #ifdef HAVE_SETENV setenv("PYTHONPATH", prepare_path("scripts", 0), 1); #else { char *s = saprintf("PYTHONPATH=%s", prepare_path("scripts", 0)); putenv(s); } #endif } Py_Initialize(); PyImport_AddModule("ekg"); if (!(ekg = Py_InitModule("ekg", ekg_methods))) return -1; PyModule_AddStringConstant(ekg, "version", VERSION); ekg_config = PyObject_NEW(PyObject, &ekg_config_type); PyModule_AddObject(ekg, "config", ekg_config); return 0; } /* * python_finalize() * * usuwa z pamięci interpreter, zwalnia pamięć itd. * * 0/-1 */ int python_finalize() { list_t l; for (l = modules; l; l = l->next) { struct module *m = l->data; xfree(m->name); if (m->deinit) { PyObject *res = PyObject_CallFunction(m->deinit, "()"); Py_XDECREF(res); Py_XDECREF(m->deinit); } } list_destroy(modules, 1); modules = NULL; Py_Finalize(); return 0; } /* * python_unload() * * usuwa z pamięci podany skrypt. * * - name - nazwa skryptu, * - quiet. * * 0/-1 */ int python_unload(const char *name, int quiet) { list_t l; if (!name) { printq("python_need_name"); return -1; } for (l = modules; l; l = l->next) { struct module *m = l->data; if (strcmp(m->name, name)) continue; gg_debug(GG_DEBUG_MISC, "m->deinit = %p, hmm?\n", m->deinit); if (m->deinit) { PyObject *res = PyObject_CallFunction(m->deinit, "()"); Py_XDECREF(res); Py_XDECREF(m->deinit); } Py_XDECREF(m->handle_msg); Py_XDECREF(m->handle_msg_own); Py_XDECREF(m->handle_connect); Py_XDECREF(m->handle_disconnect); Py_XDECREF(m->handle_status); Py_XDECREF(m->handle_status_own); Py_XDECREF(m->handle_redraw_header); Py_XDECREF(m->handle_redraw_statusbar); Py_XDECREF(m->handle_keypress); Py_XDECREF(m->handle_command_line); Py_XDECREF(m->module); list_remove(&modules, m, 1); printq("python_removed"); return 0; } printq("python_not_found", name); return -1; } /* * python_run() * * uruchamia jednorazowo skrypt pythona. * * 0/-1 */ int python_run(const char *filename, int quiet) { FILE *f = fopen(filename, "r"); if (!f) { printq("python_not_found", filename); return -1; } PyRun_SimpleFile(f, (char*) filename); fclose(f); return 0; } /* * python_get_func() * * zwraca daną funkcję modułu. */ PyObject *python_get_func(PyObject *module, const char *name) { PyObject *result = PyObject_GetAttrString(module, (char*) name); if (result && !PyCallable_Check(result)) { Py_XDECREF(result); result = NULL; } return result; } /* * python_load() * * ładuje skrypt pythona o podanej nazwie z ~/.gg/scripts * * - name - nazwa skryptu, * - quiet. * * 0/-1 */ int python_load(const char *name, int quiet) { PyObject *module, *init; struct module m; char *name2; if (!name) { printq("python_need_name"); return -1; } if (strchr(name, '/')) { printq("python_wrong_location", prepare_path("scripts", 0)); return -1; } name2 = xstrdup(name); if (strlen(name2) > 3 && !strcasecmp(name2 + strlen(name2) - 3, ".py")) name2[strlen(name2) - 3] = 0; module = PyImport_ImportModule(name2); if (!module) { printq("python_not_found", name2); PyErr_Print(); xfree(name2); return -1; } if ((init = PyObject_GetAttrString(module, "init"))) { if (PyCallable_Check(init)) { PyObject *result = PyObject_CallFunction(init, "()"); if (result) { int resulti = PyInt_AsLong(result); if (!resulti) { } Py_XDECREF(result); } else PyErr_Print(); } Py_XDECREF(init); } memset(&m, 0, sizeof(m)); m.name = xstrdup(name2); m.module = module; m.deinit = python_get_func(module, "deinit"); m.handle_msg = python_get_func(module, "handle_msg"); m.handle_msg_own = python_get_func(module, "handle_msg_own"); m.handle_connect = python_get_func(module, "handle_connect"); m.handle_disconnect = python_get_func(module, "handle_disconnect"); m.handle_status = python_get_func(module, "handle_status"); m.handle_status_own = python_get_func(module, "handle_status_own"); m.handle_redraw_header = python_get_func(module, "handle_redraw_header"); m.handle_redraw_statusbar = python_get_func(module, "handle_redraw_statusbar"); m.handle_keypress = python_get_func(module, "handle_keypress"); m.handle_command_line = python_get_func(module, "handle_command_line"); PyErr_Clear(); list_add(&modules, &m, sizeof(m)); xfree(name2); return 0; } /* * python_exec() * * wykonuje polecenie pythona. * * - command - polecenie. * * 0/-1 */ int python_exec(const char *command) { char *tmp; if (!command) return 0; tmp = saprintf("import ekg\n%s\n", command); PyRun_SimpleString(tmp); xfree(tmp); return 0; } /* * python_list() * * wyświetla listę załadowanych skryptów. * * 0/-1 */ int python_list(int quiet) { list_t l; if (!modules) printq("python_list_empty"); for (l = modules; l; l = l->next) { struct module *m = l->data; printq("python_list", m->name); } return 0; } int python_function(const char *function, const char *arg) { return -1; } void python_autorun() { const char *path = prepare_path("scripts/autorun", 0); struct dirent *d; struct stat st; char *tmp; DIR *dir; if (!(dir = opendir(path))) return; /* należy utworzyć plik ~/.gg/scripts/autorun/__init__.py, inaczej * python nie będzie można ładować skryptów przez ,,autorun.nazwa'' */ tmp = saprintf("%s/__init__.py", path); if (stat(tmp, &st)) { FILE *f = fopen(tmp, "w"); if (f) fclose(f); } xfree(tmp); while ((d = readdir(dir))) { tmp = saprintf("%s/%s", path, d->d_name); if (stat(tmp, &st) || S_ISDIR(st.st_mode)) { xfree(tmp); continue; } xfree(tmp); if (!strcmp(d->d_name, "__init__.py")) continue; if (strlen(d->d_name) < 3 || strcmp(d->d_name + strlen(d->d_name) - 3, ".py")) continue; tmp = saprintf("autorun.%s", d->d_name); tmp[strlen(tmp) - 3] = 0; python_load(tmp, 0); xfree(tmp); } closedir(dir); } ekg-1.9~pre+r2855/src/python.h000066400000000000000000000047741174410337000161140ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2003 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __PYTHON_H #define __PYTHON_H #include struct module { char *name; /* nazwa skryptu */ PyObject *module; /* obiekt modułu */ PyObject *deinit; /* funkcja deinicjalizacji */ PyObject *handle_msg; /* obsługa zdarzeń... */ PyObject *handle_connect; PyObject *handle_disconnect; PyObject *handle_status; PyObject *handle_redraw_header; PyObject *handle_redraw_statusbar; PyObject *handle_keypress; PyObject *handle_command_line; PyObject *handle_msg_own; PyObject *handle_status_own; }; #define PYTHON_HANDLE_HEADER(event, args...) \ { \ list_t __py_l; \ \ python_handle_result = -1;\ \ for (__py_l = modules; __py_l; __py_l = __py_l->next) { \ struct module *__py_m = __py_l->data; \ PyObject *__py_r; \ \ if (!__py_m->handle_##event) \ continue; \ \ __py_r = PyObject_CallFunction(__py_m->handle_##event, args); \ \ if (!__py_r) \ PyErr_Print(); \ \ python_handle_result = -1; \ \ if (__py_r && PyInt_Check(__py_r)) { \ int tmp = PyInt_AsLong(__py_r); \ \ if (python_handle_result != 2 && tmp != 1) \ python_handle_result = tmp; \ } \ \ if (__py_r && PyTuple_Check(__py_r)) #define PYTHON_HANDLE_RESULT(args...) \ if (!PyArg_ParseTuple(__py_r, args)) \ PyErr_Print(); \ else #define PYTHON_HANDLE_FOOTER() \ \ Py_XDECREF(__py_r); \ \ if (python_handle_result == 0) \ break; \ } \ } int python_handle_result; list_t modules; int python_initialize(void); int python_finalize(void); int python_load(const char *name, int quiet); int python_unload(const char *name, int quiet); int python_exec(const char *command); int python_run(const char *filename, int quiet); int python_list(int quiet); int python_function(const char *function, const char *arg); void python_autorun(void); #endif /* __PYTHON_H */ ekg-1.9~pre+r2855/src/simlite.c000066400000000000000000000252251174410337000162260ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2003 Wojtek Kaniewski * Piotr Domagalski * * Idea and concept from SIM by Michal J. Kubski available at * http://gg.wha.la/crypt/. Original source code can be found * at http://gg.wha.la/sim.tar.gz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "libgadu.h" #include "simlite.h" #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif char *sim_key_path = NULL; int sim_errno = 0; /* * sim_seed_prng() */ static int sim_seed_prng() { char rubbish[1024]; struct { time_t time; void * foo; void * foo2; } data; data.time = time(NULL); data.foo = (void *) &data; data.foo2 = (void *) rubbish; RAND_seed((void *) &data, sizeof(data)); RAND_seed((void *) rubbish, sizeof(rubbish)); return sizeof(data) + sizeof(rubbish); } /* * sim_key_generate() * * tworzy parę kluczy i zapisuje je na dysku. * * - uin - numer, dla którego generujemy klucze. * * 0/-1 */ int sim_key_generate(uint32_t uin) { char path[PATH_MAX + 1]; RSA *keys = NULL; int res = -1; FILE *f = NULL; if (!RAND_status()) sim_seed_prng(); if (!(keys = RSA_generate_key(1024, RSA_F4, NULL, NULL))) { sim_errno = SIM_ERROR_RSA; goto cleanup; } snprintf(path, sizeof(path), "%s/%d.pem", sim_key_path, uin); if (!(f = fopen(path, "w"))) { sim_errno = SIM_ERROR_PUBLIC; goto cleanup; } if (!PEM_write_RSAPublicKey(f, keys)) { sim_errno = SIM_ERROR_PUBLIC; goto cleanup; } fclose(f); f = NULL; snprintf(path, sizeof(path), "%s/private.pem", sim_key_path); if (!(f = fopen(path, "w"))) { sim_errno = SIM_ERROR_PRIVATE; goto cleanup; } if (!PEM_write_RSAPrivateKey(f, keys, NULL, NULL, 0, NULL, NULL)) { sim_errno = SIM_ERROR_PUBLIC; goto cleanup; } fclose(f); f = NULL; res = 0; cleanup: if (keys) RSA_free(keys); if (f) fclose(f); return res; } /* * sim_key_read() * * wczytuje klucz RSA podanego numer. klucz prywatny można wczytać, jeśli * zamiasr numeru poda się 0. * * - uin - numer klucza. * * zaalokowany klucz RSA, który należy zwolnić RSA_free() */ static RSA *sim_key_read(uint32_t uin) { char path[PATH_MAX + 1]; FILE *f; RSA *key; if (uin) snprintf(path, sizeof(path), "%s/%d.pem", sim_key_path, uin); else snprintf(path, sizeof(path), "%s/private.pem", sim_key_path); if (!(f = fopen(path, "r"))) return NULL; if (uin) key = PEM_read_RSAPublicKey(f, NULL, NULL, NULL); else key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL); fclose(f); return key; } /* * sim_key_fingerprint() * * zwraca fingerprint danego klucza. * * - uin - numer posiadacza klucza. * * zaalokowany bufor. */ char *sim_key_fingerprint(uint32_t uin) { RSA *key = sim_key_read(uin); unsigned char md_value[EVP_MAX_MD_SIZE], *buf, *newbuf; char *result = NULL; EVP_MD_CTX ctx; unsigned int md_len, size, i; if (!key) return NULL; if (uin) size = i2d_RSAPublicKey(key, NULL); else size = i2d_RSAPrivateKey(key, NULL); if (!(newbuf = buf = malloc(size))) { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } if (uin) size = i2d_RSAPublicKey(key, &newbuf); else size = i2d_RSAPrivateKey(key, &newbuf); EVP_DigestInit(&ctx, EVP_sha1()); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, md_value, &md_len); free(buf); if (!(result = malloc(md_len * 3))) { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } for (i = 0; i < md_len; i++) snprintf(result + i * 3, (md_len * 3 - i * 3), (i != md_len - 1) ? "%.2x:" : "%.2x", md_value[i]); cleanup: RSA_free(key); return result; } /* * sim_strerror() * * zamienia kod błędu simlite na komunikat. * * - error - kod błędu. * * zwraca statyczny bufor. */ const char *sim_strerror(int error) { const char *result = "Unknown error"; switch (error) { case SIM_ERROR_SUCCESS: result = "Success"; break; case SIM_ERROR_PUBLIC: result = "Unable to read public key"; break; case SIM_ERROR_PRIVATE: result = "Unable to read private key"; break; case SIM_ERROR_RSA: result = "RSA error"; break; case SIM_ERROR_BF: result = "Blowfish error"; break; case SIM_ERROR_RAND: result = "Not enough random data"; break; case SIM_ERROR_MEMORY: result = "Out of memory"; break; case SIM_ERROR_INVALID: result = "Invalid message format (too short, etc.)"; break; case SIM_ERROR_MAGIC: result = "Invalid magic value"; break; } return result; } /* * sim_message_encrypt() * * szyfruje wiadomość przeznaczoną dla podanej osoby, zwracając jej * zapis w base64. * * - message - treść wiadomości, * - uin - numer odbiorcy. * * zaalokowany bufor. */ char *sim_message_encrypt(const unsigned char *message, uint32_t uin) { sim_message_header head; /* nagłówek wiadomości */ unsigned char ivec[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char bf_key[16]; /* klucz symetryczny Blowfisha */ unsigned char bf_key_rsa[128]; /* symetryczny szyfrowany RSA */ BIO *mbio = NULL, *cbio = NULL, *bbio = NULL; RSA *public = NULL; int res_len; char *res = NULL, *tmp; /* wczytaj klucz publiczny delikwenta */ if (!(public = sim_key_read(uin))) { sim_errno = SIM_ERROR_PUBLIC; goto cleanup; } /* trzeba nakarmić potwora? */ if (!RAND_status()) sim_seed_prng(); /* wylosuj klucz symetryczny */ if (RAND_bytes(bf_key, sizeof(bf_key)) != 1) { sim_errno = SIM_ERROR_RAND; goto cleanup; } /* teraz go szyfruj kluczem publiczym */ if (RSA_public_encrypt(sizeof(bf_key), bf_key, bf_key_rsa, public, RSA_PKCS1_OAEP_PADDING) == -1) { sim_errno = SIM_ERROR_RSA; goto cleanup; } /* przygotuj zawartość pakietu do szyfrowania blowfishem */ memset(&head, 0, sizeof(head)); head.magic = gg_fix16(SIM_MAGIC_V1); if (RAND_bytes(head.init, sizeof(head.init)) != 1) { sim_errno = SIM_ERROR_RAND; goto cleanup; } /* przygotuj base64 */ mbio = BIO_new(BIO_s_mem()); bbio = BIO_new(BIO_f_base64()); BIO_set_flags(bbio, BIO_FLAGS_BASE64_NO_NL); BIO_push(bbio, mbio); /* mamy już klucz symetryczny szyfrowany przez rsa, więc możemy * go wrzucić do base64 */ BIO_write(bbio, bf_key_rsa, sizeof(bf_key_rsa)); /* teraz będziemy szyfrować blowfishem */ cbio = BIO_new(BIO_f_cipher()); BIO_set_cipher(cbio, EVP_bf_cbc(), bf_key, ivec, 1); BIO_push(cbio, bbio); BIO_write(cbio, &head, sizeof(head)); BIO_write(cbio, message, strlen((char*) message)); BIO_flush(cbio); /* zachowaj wynik */ res_len = BIO_get_mem_data(mbio, (unsigned char*) &tmp); if (!(res = malloc(res_len + 1))) { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } memcpy(res, tmp, res_len); res[res_len] = 0; sim_errno = SIM_ERROR_SUCCESS; cleanup: /* zwolnij pamięć */ if (bbio) BIO_free(bbio); if (mbio) BIO_free(mbio); if (cbio) BIO_free(cbio); if (public) RSA_free(public); return res; } /* * sim_message_decrypt() * * odszyfrowuje wiadomość od podanej osoby. * * - message - treść wiadomości, * - uin - numer nadawcy. * * zaalokowany bufor. */ char *sim_message_decrypt(const unsigned char *message, uint32_t uin) { sim_message_header head; /* nagłówek wiadomości */ unsigned char ivec[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char bf_key[16]; /* klucz symetryczny Blowfisha */ unsigned char bf_key_rsa[128]; /* symetryczny szyfrowany RSA */ BIO *mbio = NULL, *cbio = NULL, *bbio = NULL; RSA *private = NULL; unsigned char *buf = NULL, *res = NULL, *data, *all_data = NULL; int len, all_data_length = 0; /* jeśli wiadomość jest krótsza niż najkrótsza zaszyfrowana, * nie ma sensu się bawić w próby odszyfrowania. */ if (strlen((char*) message) < 192) { sim_errno = SIM_ERROR_INVALID; goto cleanup; } /* wczytaj klucz prywatny */ if (!(private = sim_key_read(0))) { sim_errno = SIM_ERROR_PRIVATE; goto cleanup; } mbio = BIO_new(BIO_s_mem()); bbio = BIO_new(BIO_f_base64()); BIO_set_flags(bbio, BIO_FLAGS_BASE64_NO_NL); BIO_push(bbio, mbio); BIO_write(mbio, message, strlen((char *) message)); BIO_flush(mbio); if (BIO_read(bbio, bf_key_rsa, sizeof(bf_key_rsa)) < sizeof(bf_key_rsa)) { sim_errno = SIM_ERROR_INVALID; goto cleanup; } if (RSA_private_decrypt(sizeof(bf_key_rsa), bf_key_rsa, bf_key, private, RSA_PKCS1_OAEP_PADDING) == -1) { sim_errno = SIM_ERROR_RSA; goto cleanup; } len = BIO_pending(bbio); if (!(buf = malloc(len))) { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } if (!(all_data = malloc(len))) { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } if (len < sizeof(head)) { sim_errno = SIM_ERROR_INVALID; goto cleanup; } if ((len = BIO_read(bbio, buf, len)) == -1) { sim_errno = SIM_ERROR_INVALID; goto cleanup; } all_data_length = len; memcpy(all_data, buf, len); while ((len = BIO_read(bbio, buf, len)) > 0) { unsigned char *tmp = realloc(all_data, all_data_length + len); if (tmp) { all_data = tmp; memcpy(all_data + all_data_length, buf, len); all_data_length += len; } else { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } } BIO_free(bbio); bbio = NULL; BIO_free(mbio); mbio = NULL; free(buf); buf = NULL; /* odszyfruj blowfisha */ mbio = BIO_new(BIO_s_mem()); cbio = BIO_new(BIO_f_cipher()); BIO_set_cipher(cbio, EVP_bf_cbc(), bf_key, ivec, 0); BIO_push(cbio, mbio); BIO_write(cbio, all_data, all_data_length); BIO_flush(cbio); free(all_data); all_data = NULL; len = BIO_get_mem_data(mbio, &data); if (len < sizeof(head)) { sim_errno = SIM_ERROR_INVALID; goto cleanup; } memcpy(&head, data, sizeof(head)); if (head.magic != gg_fix16(SIM_MAGIC_V1)) { sim_errno = SIM_ERROR_MAGIC; goto cleanup; } len -= sizeof(head); if (!(res = malloc(len + 1))) { sim_errno = SIM_ERROR_MEMORY; goto cleanup; } memcpy(res, data + sizeof(head), len); res[len] = 0; cleanup: if (cbio) BIO_free(cbio); if (mbio) BIO_free(mbio); if (bbio) BIO_free(bbio); if (private) RSA_free(private); if (buf) free(buf); if (all_data) free(all_data); return (char *) res; } ekg-1.9~pre+r2855/src/simlite.h000066400000000000000000000033331174410337000162270ustar00rootroot00000000000000/* * (C) Copyright 2003 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __SIMLITE_H #define __SIMLITE_H #include extern char *sim_key_path; extern int sim_errno; enum sim_errno_type { SIM_ERROR_SUCCESS, /* udało się */ SIM_ERROR_PUBLIC, /* błąd klucza publicznego */ SIM_ERROR_PRIVATE, /* błąd klucza prywatnego */ SIM_ERROR_RSA, /* nie udało się odszyfrować RSA */ SIM_ERROR_BF, /* nie udało się odszyfrować BF */ SIM_ERROR_RAND, /* entropia poszła na piwo */ SIM_ERROR_MEMORY, /* brak pamięci */ SIM_ERROR_INVALID, /* niewłaściwa wiadomość (za krótka) */ SIM_ERROR_MAGIC /* niewłaściwy magic */ }; #define SIM_MAGIC_V1 0x2391 typedef struct { unsigned char init[8]; uint16_t magic; uint8_t flags; } #ifdef __GNUC__ __attribute__ ((packed)) #endif sim_message_header; char *sim_message_decrypt(const unsigned char *message, uint32_t uin); char *sim_message_encrypt(const unsigned char *message, uint32_t uin); int sim_key_generate(uint32_t uin); char *sim_key_fingerprint(uint32_t uin); const char *sim_strerror(int error); #endif /* __SIMLITE_H */ ekg-1.9~pre+r2855/src/stuff.c000066400000000000000000002230011174410337000156770ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2005 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * Piotr Kupisiewicz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #ifdef WITH_IOCTLD # include # include "ioctld.h" #endif #include #include #include #ifdef HAVE_LIBGEN_H # include #else # include "../compat/dirname.h" #endif #include #include #include #include #include #include #include #include "commands.h" #include "compat.h" #include "dynstuff.h" #include "libgadu.h" #ifdef HAVE_OPENSSL # include "simlite.h" #endif #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "userlist.h" #include "vars.h" #include "xmalloc.h" #ifdef WITH_PYTHON # include "python.h" #endif #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif struct gg_session *sess = NULL; list_t autofinds = NULL; list_t children = NULL; list_t aliases = NULL; list_t watches = NULL; list_t transfers = NULL; list_t events = NULL; list_t bindings = NULL; list_t timers = NULL; list_t conferences = NULL; list_t sms_away = NULL; list_t buffers = NULL; list_t searches = NULL; list_t spiedlist = NULL; int command_processing = 0; int in_autoexec = 0; int no_autorun = 0; int in_auto_away = 0; int config_auto_reconnect = 10; int reconnect_timer = 0; int config_auto_away = 600; int config_auto_away_keep_descr = 1; int config_auto_save = 0; int config_auto_find = 0; int config_auto_conference = 1; time_t last_save = 0; int config_display_color = 1; int config_beep = 1; int config_beep_msg = 1; int config_beep_chat = 1; int config_beep_notify = 1; int config_beep_mail = 1; int config_display_pl_chars = 1; int config_events_delay = 3; int config_files_mode_config_int = 600; /* nie 0600, bo jest zamieniane z dec na oct */ int config_files_mode_config = 0600; /* wartosc oktalna files_mode_config */ int config_files_mode_received_int = 600; int config_files_mode_received = 0600; char *config_sound_msg_file = NULL; char *config_sound_chat_file = NULL; char *config_sound_sysmsg_file = NULL; char *config_sound_notify_file = NULL; char *config_sound_mail_file = NULL; char *config_sound_app = NULL; int config_uin = 0; int config_userlist_backup = 0; int config_last_sysmsg = 0; int config_last_sysmsg_changed = 0; char *config_local_ip = NULL; char *config_password = NULL; int config_slash_messages = 1; int config_sms_away = 0; int config_sms_away_limit = 0; char *config_sms_number = NULL; char *config_sms_app = NULL; int config_sms_max_length = 100; int config_changed = 0; int config_display_ack = 3; int config_completion_notify = 1; int connecting = 0; time_t last_conn_event = 0; time_t ekg_started = 0; int config_display_daychanges = 1; int config_display_notify = 1; char *config_theme = NULL; int config_status = GG_STATUS_AVAIL; char *reg_password = NULL; char *reg_email = NULL; int config_dcc = 0; int config_dcc_backups = 0; char *config_dcc_ip = NULL; char *config_dcc_dir = NULL; int config_dcc_port = GG_DEFAULT_DCC_PORT; char *config_reason = NULL; char *home_dir = NULL; char *config_quit_reason = NULL; char *config_away_reason = NULL; char *config_back_reason = NULL; char *config_ffc_reason = NULL; char *config_dnd_reason = NULL; int config_random_reason = 0; #ifdef HAVE_REGEX_H int config_regex_flags = 0; #endif int config_query_commands = 0; char *config_proxy = NULL; char *config_server = NULL; int quit_message_send = 0; int registered_today = 0; int config_protocol = 0; int pipe_fd = -1; int batch_mode = 0; char *batch_line = NULL; int config_make_window = 2; char *config_tab_command = NULL; int ioctld_sock = -1; int config_ctrld_quits = 1; int config_save_password = 1; int config_receive_images = 0; int config_image_size = 255; int config_save_question = 1; char *config_datestamp = NULL; char *config_timestamp = NULL; int config_display_sent = 1; int config_sort_windows = 0; int config_keep_reason = 0; int config_enter_scrolls = 0; int server_index = 0; char *config_audio_device = NULL; char *config_speech_app = NULL; int config_encryption = 0; int config_server_save = 0; char *config_email = NULL; int config_time_deviation = 300; int config_msg_as_chat = 0; int config_mesg = MESG_DEFAULT; #ifdef WITH_UI_NCURSES int config_mouse = 0; #endif char *config_nick = NULL; int config_display_welcome = 1; int config_auto_back = 0; int config_display_crap = 1; char *config_display_color_map = NULL; int config_windows_save = 0; char *config_windows_layout = NULL; char *config_profile = NULL; int config_header_size = 0; int config_status_window = 0; int config_statusbar_size = 1; int config_statusbar_fgcolor = 7; int config_statusbar_bgcolor = 4; char *config_proxy_forwarding = NULL; int config_password_cp1250 = 0; char *config_interface = NULL; int config_reason_limit = 0; char *config_dcc_limit = NULL; int config_ignore_unknown_sender = 0; int config_ignore_empty_msg = 0; #ifdef WITH_WAP int config_wap_enabled = 2; #endif #if defined HAVE_LIBJPEG || defined HAVE_LIBUNGIF int config_display_token = 1; #endif #ifdef WITH_IOCTLD int config_ioctld_enable = 1; int config_ioctld_net_port = 22004; #endif int config_dcc_filter = 1; char *last_search_first_name = NULL; char *last_search_last_name = NULL; char *last_search_nickname = NULL; uin_t last_search_uin = 0; char *last_tokenid = NULL; struct event_label event_labels[EVENT_LABELS_COUNT + 2] = { { EVENT_MSG, "msg" }, { EVENT_CHAT, "chat" }, { EVENT_CONFERENCE, "conference" }, { EVENT_QUERY, "query" }, { EVENT_AVAIL, "avail" }, { EVENT_ONLINE, "online" }, { EVENT_NOT_AVAIL, "notavail" }, { EVENT_AWAY, "away" }, { EVENT_INVISIBLE, "invisible" }, { EVENT_DESCR, "descr" }, { EVENT_DCC, "dcc" }, { EVENT_SIGUSR1, "sigusr1" }, { EVENT_SIGUSR2, "sigusr2" }, { EVENT_DELIVERED, "delivered" }, { EVENT_QUEUED, "queued" }, { EVENT_FILTERED, "filtered" }, { EVENT_MBOXFULL, "mboxfull" }, { EVENT_NOT_DELIVERED, "not_delivered" }, { EVENT_NEWMAIL, "newmail" }, { EVENT_BLOCKED, "blocked" }, { EVENT_DCCFINISH, "dccfinish" }, { EVENT_CONNECTED, "connected" }, { EVENT_DISCONNECTED, "disconnected" }, { EVENT_CONNECTIONLOST, "connectionlost" }, { EVENT_IMAGE, "image" }, { INACTIVE_EVENT, NULL }, { 0, NULL } }; /* * alias_add() * * dopisuje alias do listy aliasów. * * - string - linia w formacie 'alias cmd', * - quiet - czy wypluwać mesgi na stdout, * - append - czy dodajemy kolejną komendę? * * 0/-1 */ int alias_add(const char *string, int quiet, int append) { char *cmd; list_t l; struct alias a; char *params = NULL; if (!string || !(cmd = strchr(string, ' '))) return -1; *cmd++ = 0; for (l = aliases; l; l = l->next) { struct alias *j = l->data; if (!strcasecmp(string, j->name)) { if (!append) { printq("aliases_exist", string); return -1; } else { list_t l; list_add(&j->commands, cmd, strlen(cmd) + 1); /* przy wielu komendach trudno dopełniać, bo według której? */ for (l = commands; l; l = l->next) { struct command *c = l->data; if (!strcasecmp(c->name, j->name)) { xfree(c->params); c->params = xstrdup("?"); break; } } printq("aliases_append", string); return 0; } } } for (l = commands; l; l = l->next) { struct command *c = l->data; char *tmp = ((*cmd == '/') ? cmd + 1 : cmd); if (!strcasecmp(string, c->name) && !c->alias) { printq("aliases_command", string); return -1; } if (!strncasecmp(tmp, c->name, strlen(c->name))) { params = xstrdup(c->params); break; } } a.name = xstrdup(string); a.commands = NULL; list_add(&a.commands, cmd, strlen(cmd) + 1); list_add(&aliases, &a, sizeof(a)); command_add(a.name, ((params) ? params: "?"), cmd_alias_exec, 1, "", "", ""); xfree(params); printq("aliases_add", a.name, ""); return 0; } /* * alias_remove() * * usuwa alias z listy aliasów. * * - name - alias lub NULL, * - quiet. * * 0/-1 */ int alias_remove(const char *name, int quiet) { list_t l; int removed = 0; for (l = aliases; l; ) { struct alias *a = l->data; l = l->next; if (!name || !strcasecmp(a->name, name)) { if (name) printq("aliases_del", name); command_remove(a->name); xfree(a->name); list_destroy(a->commands, 1); list_remove(&aliases, a, 1); removed = 1; } } if (!removed) { if (name) printq("aliases_noexist", name); else printq("aliases_list_empty"); return -1; } if (removed && !name) printq("aliases_del_all"); return 0; } /* * alias_free() * * zwalnia pamięć zajętą przez aliasy. */ void alias_free() { list_t l; if (!aliases) return; for (l = aliases; l; l = l->next) { struct alias *a = l->data; xfree(a->name); list_destroy(a->commands, 1); } list_destroy(aliases, 1); aliases = NULL; } static const char base64_charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * base64_encode() * * zapisuje ciąg znaków w base64. alokuje pamięć. */ char *base64_encode(const char *buf) { char *out, *res; unsigned int i = 0, j = 0, k = 0, len; if (!buf) return xstrdup(""); len = strlen(buf); res = out = xmalloc((len / 3 + 1) * 4 + 2); while (j <= len) { switch (i % 4) { case 0: k = (buf[j] & 252) >> 2; break; case 1: if (j < len) k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4); else k = (buf[j] & 3) << 4; j++; break; case 2: if (j < len) k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6); else k = (buf[j] & 15) << 2; j++; break; case 3: k = buf[j++] & 63; break; } *out++ = base64_charset[k]; i++; } if (i % 4) for (j = 0; j < 4 - (i % 4); j++, out++) *out = '='; *out = 0; return res; } /* * base64_decode() * * wczytuje ciąg znaków base64, zwraca zaalokowany buforek. */ char *base64_decode(const char *buf) { char *res, *save, val; const char *foo; const char *end; unsigned int index = 0; if (!buf) return xstrdup(""); save = res = xcalloc(1, (strlen(buf) / 4 + 1) * 3 + 2); end = buf + strlen(buf); while (*buf && buf < end) { if (*buf == '\r' || *buf == '\n') { buf++; continue; } if (!(foo = strchr(base64_charset, *buf))) foo = base64_charset; val = (int)(foo - base64_charset); buf++; switch (index) { case 0: *res |= val << 2; break; case 1: *res++ |= val >> 4; *res |= val << 4; break; case 2: *res++ |= val >> 2; *res |= val << 6; break; case 3: *res++ |= val; break; } index++; index %= 4; } *res = 0; return save; } /* * binding_list() * * wyświetla listę przypisanych komend. */ void binding_list(int quiet, const char *name, int all) { list_t l; int found = 0; if (!bindings) printq("bind_seq_list_empty"); for (l = bindings; l; l = l->next) { struct binding *b = l->data; if (name) { if (strcasestr(b->key, name)) { printq("bind_seq_list", b->key, b->action); found = 1; } continue; } if (!b->internal || (all && b->internal)) printq("bind_seq_list", b->key, b->action); } if (name && !found) { for (l = bindings; l; l = l->next) { struct binding *b = l->data; if (strcasestr(b->action, name)) printq("bind_seq_list", b->key, b->action); } } } /* * binding_free() * * zwalnia pamięć po liście przypisanych klawiszy. */ void binding_free() { list_t l; if (!bindings) return; for (l = bindings; l; l = l->next) { struct binding *b = l->data; xfree(b->key); xfree(b->action); xfree(b->arg); xfree(b->default_action); xfree(b->default_arg); } list_destroy(bindings, 1); bindings = NULL; } /* * buffer_add() * * dodaje linijkę do danego typu bufora. jeśli max_lines > 0 * to pilnuje, aby w buforze było maksymalnie tyle linii. * * - type, * - line, * - max_lines. * * 0/-1 */ int buffer_add(int type, const char *target, const char *line, int max_lines) { struct buffer b; if (max_lines && buffer_count(type) >= max_lines) { struct buffer *foo = buffers->data; xfree(foo->line); list_remove(&buffers, foo, 1); } b.type = type; b.target = xstrdup(target); b.line = xstrdup(line); return ((list_add(&buffers, &b, sizeof(b)) ? 0 : -1)); } /* * buffer_flush() * * zwraca zaalokowany łancuch zawierający wszystkie linie * z bufora danego typu. * * - type, * - target - dla kogo był bufor? NULL, jeśli olewamy. */ char *buffer_flush(int type, const char *target) { string_t str = string_init(NULL); list_t l; for (l = buffers; l; ) { struct buffer *b = l->data; l = l->next; if (type != b->type) continue; if (target && b->target && strcmp(target, b->target)) continue; string_append(str, b->line); string_append_c(str, '\r'); string_append_c(str, '\n'); xfree(b->line); xfree(b->target); list_remove(&buffers, b, 1); } return string_free(str, 0); } /* * buffer_count() * * zwraca liczbę linii w buforze danego typu. */ int buffer_count(int type) { list_t l; int count = 0; for (l = buffers; l; l = l->next) { struct buffer *b = l->data; if (b->type == type) count++; } return count; } /* * buffer_tail() * * zwraca najstarszy element buforowej kolejki, który * należy zwolnić. usuwa go z kolejki. zwraca NULL, * gdy kolejka jest pusta. */ char *buffer_tail(int type) { char *str = NULL; list_t l; for (l = buffers; l; l = l->next) { struct buffer *b = l->data; if (type != b->type) continue; str = xstrdup(b->line); xfree(b->target); list_remove(&buffers, b, 1); break; } return str; } /* * buffer_free() * * zwalnia pamięć po buforach. */ void buffer_free() { list_t l; if (!buffers) return; for (l = buffers; l; l = l->next) { struct buffer *b = l->data; xfree(b->line); xfree(b->target); } list_destroy(buffers, 1); buffers = NULL; } /* * changed_auto_save() * * wywoływane po zmianie wartości zmiennej ,,auto_save''. */ void changed_auto_save(const char *var) { /* oszukujemy, ale takie zachowanie wydaje się być bardziej ,,naturalne'' */ last_save = time(NULL); } /* * changed_aspell() * * wywoływane po zmianie wartości zmiennej ,,aspell'' lub ,,aspell_lang'' lub ,,aspell_encoding''. */ #ifdef WITH_ASPELL void changed_aspell(const char *var) { if (config_aspell == 1) { spellcheck_init(); } else { spellcheck_deinit(); } } #endif /* * changed_backlog_size() * * wywoływane po zmianie wartości zmiennej ,,backlog_size''. */ void changed_backlog_size(const char *var) { #ifdef WITH_UI_NCURSES if (config_backlog_size < ui_screen_height) config_backlog_size = ui_screen_height; #endif } /* * changed_dcc() * * funkcja wywoływana przy zmianie wartości zmiennej ,,dcc''. */ void changed_dcc(const char *var) { struct gg_dcc *dcc = NULL; list_t l; if (!config_uin) return; if (!strcmp(var, "dcc")) { for (l = watches; l; l = l->next) { struct gg_common *c = l->data; if (c->type == GG_SESSION_DCC_SOCKET) dcc = l->data; } if (!config_dcc && dcc) { list_remove(&watches, dcc, 0); gg_free_dcc(dcc); gg_dcc_ip = 0; gg_dcc_port = 0; } if (config_dcc && !dcc) { if (!(dcc = gg_dcc_socket_create(config_uin, config_dcc_port))) { print("dcc_create_error", strerror(errno)); } else { list_add(&watches, dcc, 0); } } } if (!strcmp(var, "dcc_ip")) { if (config_dcc_ip) { if (!strcasecmp(config_dcc_ip, "auto")) { gg_dcc_ip = inet_addr("255.255.255.255"); } else { if (inet_addr(config_dcc_ip) != INADDR_NONE) gg_dcc_ip = inet_addr(config_dcc_ip); else { print("dcc_invalid_ip"); xfree(config_dcc_ip); config_dcc_ip = NULL; gg_dcc_ip = 0; } } } else gg_dcc_ip = 0; } if (!strcmp(var, "dcc_port")) { for (l = watches; l; l = l->next) { struct gg_common *c = l->data; if (c->type == GG_SESSION_DCC_SOCKET) dcc = l->data; } if (config_dcc && dcc && (dcc->port != config_dcc_port)) { list_remove(&watches, dcc, 0); gg_free_dcc(dcc); gg_dcc_ip = 0; gg_dcc_port = 0; if (!(dcc = gg_dcc_socket_create(config_uin, config_dcc_port))) { print("dcc_create_error", strerror(errno)); } else { list_add(&watches, dcc, 0); } } } if (sess && sess->state == GG_STATE_CONNECTED) print("dcc_must_reconnect"); update_status_myip(); } /* * changed_local_ip() * * funkcja wywoływana przy zmianie wartości zmiennej ,,local_ip''. */ void changed_local_ip(const char *var) { if (config_local_ip == NULL) gg_local_ip = htonl(INADDR_ANY); else { #ifdef HAVE_INET_PTON int tmp = inet_pton(AF_INET, config_local_ip, &gg_local_ip); if (tmp == 0 || tmp == -1) { print("invalid_local_ip"); xfree(config_local_ip); config_local_ip = NULL; gg_local_ip = htonl(INADDR_ANY); } #else gg_local_ip = inet_addr(config_local_ip); #endif } } /* * changed_mesg() * * funkcja wywoływana przy zmianie wartości zmiennej ,,mesg''. */ void changed_mesg(const char *var) { if (config_mesg == MESG_DEFAULT) mesg_set(mesg_startup); else mesg_set(config_mesg); } /* * changed_proxy() * * funkcja wywoływana przy zmianie wartości zmiennej ,,proxy''. */ void changed_proxy(const char *var) { char **auth, **userpass = NULL, **hostport = NULL; gg_proxy_port = 0; xfree(gg_proxy_host); gg_proxy_host = NULL; xfree(gg_proxy_username); gg_proxy_username = NULL; xfree(gg_proxy_password); gg_proxy_password = NULL; gg_proxy_enabled = 0; if (!config_proxy) return; auth = array_make(config_proxy, "@", 0, 0, 0); if (!auth[0] || !strcmp(auth[0], "")) { array_free(auth); return; } gg_proxy_enabled = 1; if (auth[0] && auth[1]) { userpass = array_make(auth[0], ":", 0, 0, 0); hostport = array_make(auth[1], ":", 0, 0, 0); } else hostport = array_make(auth[0], ":", 0, 0, 0); if (userpass && userpass[0] && userpass[1]) { gg_proxy_username = xstrdup(userpass[0]); gg_proxy_password = xstrdup(userpass[1]); } gg_proxy_host = xstrdup(hostport[0]); gg_proxy_port = (hostport[1]) ? atoi(hostport[1]) : 8080; array_free(hostport); array_free(userpass); array_free(auth); } /* * changed_theme() * * funkcja wywoływana przy zmianie wartości zmiennej ,,theme''. */ void changed_theme(const char *var) { if (!config_theme) { theme_free(); theme_init(); ui_event("theme_init"); } else { if (!theme_read(config_theme, 1)) { if (!in_autoexec) print("theme_loaded", config_theme); } else print("error_loading_theme", strerror(errno)); } } /* * changed_uin() * * funkcja wywoływana przy zmianie zmiennej uin. */ void changed_uin(const char *var) { ui_event("xterm_update"); } /* * changed_xxx_reason() * * funkcja wywoływana przy zmianie domyślnych powodów. */ void changed_xxx_reason(const char *var) { char *tmp = NULL; if (!strcmp(var, "away_reason")) tmp = config_away_reason; if (!strcmp(var, "back_reason")) tmp = config_back_reason; if (!strcmp(var, "dnd_reason")) tmp = config_dnd_reason; if (!strcmp(var, "ffc_reason")) tmp = config_ffc_reason; if (!strcmp(var, "quit_reason")) tmp = config_quit_reason; if (!tmp) return; if (strlen(tmp) > GG_STATUS_DESCR_MAXSIZE) print("descr_too_long", itoa(strlen(tmp) - GG_STATUS_DESCR_MAXSIZE)); } /* * changed_files_mode() * * funkcja wywołwana przy zmianie config_files_mode_*_int */ void changed_files_mode(const char *var) { char mode[16]; snprintf(mode, sizeof(mode), "%d", config_files_mode_config_int); config_files_mode_config = strtol(mode, NULL, 8); snprintf(mode, sizeof(mode), "%d", config_files_mode_received_int); config_files_mode_received = strtol(mode, NULL, 8); } /* * conference_add() * * dopisuje konferencje do listy konferencji. * * - name - nazwa konferencji, * - nicklist - lista nicków, grup, czegokolwiek, * - quiet - czy wypluwać mesgi na stdout. * * zaalokowaną struct conference lub NULL w przypadku błędu. */ struct conference *conference_add(const char *name, const char *nicklist, int quiet) { struct conference c, *ret; char **nicks, **p; list_t l; int i, count; memset(&c, 0, sizeof(c)); if (!name || !nicklist) return NULL; if (nicklist[0] == ',' || nicklist[strlen(nicklist) - 1] == ',') { printq("invalid_params", "chat"); return NULL; } nicks = array_make(nicklist, " ,", 0, 1, 1); /* grupy zamieniamy na niki */ for (i = 0; nicks[i]; i++) { if (nicks[i][0] == '@') { char *gname = xstrdup(nicks[i] + 1); int first = 0; int nig = 0; /* nicks in group */ for (l = userlist; l; l = l->next) { struct userlist *u = l->data; list_t m; if (!u->display) continue; for (m = u->groups; m; m = m->next) { struct group *g = m->data; if (!strcasecmp(gname, g->name)) { if (first++) { if (!array_contains(nicks, u->display, 0)) array_add(&nicks, xstrdup(u->display)); } else { xfree(nicks[i]); nicks[i] = xstrdup(u->display); } nig++; break; } } } if (!nig) { printq("group_empty", gname); printq("conferences_not_added", name); xfree(gname); array_free(nicks); return NULL; } xfree(gname); } } count = array_count(nicks); for (l = conferences; l; l = l->next) { struct conference *cf = l->data; if (!strcasecmp(name, cf->name)) { printq("conferences_exist", name); array_free(nicks); return NULL; } } for (p = nicks, i = 0; *p; p++) { uin_t uin; list_t l; if (!strcmp(*p, "")) continue; if (!(uin = get_uin(*p))) { printq("user_not_found", *p); break; } if (uin == config_uin) break; for (l = c.recipients; l; l = l->next) { uin_t tmp = *((uin_t *)l->data); if (tmp == uin) { uin = 0; break; } } if (!uin) break; list_add(&(c.recipients), &uin, sizeof(uin)); i++; } array_free(nicks); if (i != count) { printq("conferences_not_added", name); if (c.recipients) list_destroy(c.recipients, 1); return NULL; } printq("conferences_add", name); c.name = xstrdup(name); add_send_nick(name); ret = list_add(&conferences, &c, sizeof(c)); event_check(EVENT_CONFERENCE, 0, name); /* jeśli na liście zdarzeń jest usunięcie konferencji, to ret już nie * wskazuje na nic sensownego. nie tworzymy konferencji. może trochę * mało eleganckie rozwiązanie, ale nie przychodzi mi do głowy nic * lepszego. -- gophi */ { list_t cur = conferences; while (cur) { if ((void *) ret == cur->data) return ret; cur = cur->next; } } return (struct conference *) NULL; } /* * conference_remove() * * usuwa konferencję z listy konferencji. * * - name - konferencja lub NULL dla wszystkich, * - quiet. * * 0/-1 */ int conference_remove(const char *name, int quiet) { list_t l; int removed = 0; for (l = conferences; l; ) { struct conference *c = l->data; l = l->next; if (!name || !strcasecmp(c->name, name)) { if (name) printq("conferences_del", name); remove_send_nick(c->name); xfree(c->name); list_destroy(c->recipients, 1); list_remove(&conferences, c, 1); removed = 1; } } if (!removed) { if (name) printq("conferences_noexist", name); else printq("conferences_list_empty"); return -1; } if (removed && !name) printq("conferences_del_all"); return 0; } /* * conference_create() * * tworzy nową konferencję z wygenerowaną nazwą. * * - nicks - lista ników tak, jak dla polecenia conference. */ struct conference *conference_create(const char *nicks) { struct conference *c; static int count = 1; char *name = saprintf("#conf%d", count); if ((c = conference_add(name, nicks, 0))) count++; xfree(name); return c; } /* * conference_find() * * znajduje i zwraca wskaźnik do konferencji lub NULL. * * - name - nazwa konferencji. */ struct conference *conference_find(const char *name) { list_t l; for (l = conferences; l; l = l->next) { struct conference *c = l->data; if (!strcmp(c->name, name)) return c; } return NULL; } /* * conference_participant() * * sprawdza, czy dany numer jest uczestnikiem konferencji. * * - c - konferencja, * - uin - numer. * * 1 jeśli jest, 0 jeśli nie. */ int conference_participant(struct conference *c, uin_t uin) { list_t l; for (l = c->recipients; l; l = l->next) { uin_t *u = l->data; if (uin == *u) return 1; } return 0; } /* * conference_find_by_uins() * * znajduje konferencję, do której należą podane uiny. jeżeli nie znaleziono, * zwracany jest NULL. jeśli numerów jest więcej, zostaną dodane do * konferencji, bo najwyraźniej ktoś do niej dołączył. * * - from - kto jest nadawcą wiadomości, * - recipients - tablica numerów należących do konferencji, * - count - ilość numerów, * - quiet. */ struct conference *conference_find_by_uins(uin_t from, uin_t *recipients, int count, int quiet) { int i; list_t l; for (l = conferences; l; l = l->next) { struct conference *c = l->data; int matched = 0; for (i = 0; i < count; i++) if (conference_participant(c, recipients[i])) matched++; if (conference_participant(c, from)) matched++; gg_debug(GG_DEBUG_MISC, "// conference_find_by_uins(): from=%d, rcpt count=%d, matched=%d, list_count(c->recipients)=%d\n", from, count, matched, list_count(c->recipients)); if (matched == list_count(c->recipients) && matched <= (from == config_uin ? count : count + 1)) { string_t new = string_init(NULL); int comma = 0; if (from != config_uin && !conference_participant(c, from)) { list_add(&c->recipients, &from, sizeof(from)); comma++; string_append(new, format_user(from)); } for (i = 0; i < count; i++) { if (recipients[i] != config_uin && !conference_participant(c, recipients[i])) { list_add(&c->recipients, &recipients[i], sizeof(recipients[0])); if (comma++) string_append(new, ", "); string_append(new, format_user(recipients[i])); } } if (strcmp(new->str, "") && !c->ignore) printq("conferences_joined", new->str, c->name); string_free(new, 1); gg_debug(GG_DEBUG_MISC, "// conference_find_by_uins(): matching %s\n", c->name); return c; } } return NULL; } /* * conference_set_ignore() * * ustawia stan konferencji na ignorowany lub nie. * * - name - nazwa konferencji, * - flag - 1 ignorować, 0 nie ignorować, * - quiet. * * 0/-1 */ int conference_set_ignore(const char *name, int flag, int quiet) { struct conference *c = conference_find(name); if (!c) { printq("conferences_noexist", name); return -1; } c->ignore = flag; printq((flag ? "conferences_ignore" : "conferences_unignore"), name); return 0; } /* * conference_rename() * * zmienia nazwę instniejącej konferencji. * * - oldname - stara nazwa, * - newname - nowa nazwa, * - quiet. * * 0/-1 */ int conference_rename(const char *oldname, const char *newname, int quiet) { struct conference *c; if (conference_find(newname)) { printq("conferences_exist", newname); return -1; } if (!(c = conference_find(oldname))) { printq("conference_noexist", oldname); return -1; } xfree(c->name); c->name = xstrdup(newname); remove_send_nick(oldname); add_send_nick(newname); printq("conferences_rename", oldname, newname); ui_event("conference_rename", oldname, newname, NULL); return 0; } /* * conference_free() * * zwalnia pamięć zajętą przez konferencje. */ void conference_free() { list_t l; if (!conferences) return; for (l = conferences; l; l = l->next) { struct conference *c = l->data; xfree(c->name); list_destroy(c->recipients, 1); } list_destroy(conferences, 1); conferences = NULL; } /* * ekg_connect() * * przygotowuje wszystko pod połączenie gg_login i łączy się. */ void ekg_connect() { list_t l; struct gg_login_params p; for (l = watches; l; l = l->next) { struct gg_dcc *d = l->data; if (d->type == GG_SESSION_DCC_SOCKET) { gg_dcc_port = d->port; } } memset(&p, 0, sizeof(p)); p.uin = config_uin; p.password = config_password; p.status = config_status; p.status_descr = config_reason; p.async = 1; p.image_size = config_image_size < 255 ? config_image_size : 255; #ifdef HAVE_VOIP p.has_audio = 1; #endif p.protocol_version = config_protocol; p.last_sysmsg = config_last_sysmsg; p.protocol_features = GG_FEATURE_STATUS80 | GG_FEATURE_DND_FFC; /* bez GG_FEATURE_MSG80 */ if (config_server) { char *server, *sserver, *tmp, **servers = array_make(config_server, ",; ", 0, 1, 0); #ifdef __GG_LIBGADU_HAVE_OPENSSL if (!strcasecmp(config_server, "tls")) { p.tls = 1; goto skip_server; } #endif if (server_index >= array_count(servers)) server_index = 0; if (!servers[server_index]) goto skip_server; server = sserver = xstrdup(servers[server_index++]); if (!strncasecmp(server, "tls:", 4)) { #ifdef __GG_LIBGADU_HAVE_OPENSSL p.tls = 1; #endif server += 4; } tmp = strchr(server, ':'); if (tmp) { p.server_port = atoi(tmp + 1); *tmp = 0; p.server_addr = inet_addr(server); } else { p.server_port = GG_DEFAULT_PORT; p.server_addr = inet_addr(server); } xfree(sserver); skip_server: array_free(servers); } if (config_proxy_forwarding) { char *fwd = xstrdup(config_proxy_forwarding), *tmp = strchr(fwd, ':'); if (!tmp) { p.external_addr = inet_addr(fwd); p.external_port = gg_dcc_port; } else { *tmp = 0; p.external_addr = inet_addr(fwd); p.external_port = atoi(tmp + 1); } xfree(fwd); } if (!config_password_cp1250) iso_to_cp((unsigned char *) p.password); if (p.status_descr) iso_to_cp((unsigned char *) p.status_descr); if (!(sess = gg_login(&p))) { print("conn_failed", format_find((errno == ENOMEM) ? "conn_failed_memory" : "conn_failed_connecting")); ekg_reconnect(); } else list_add(&watches, sess, 0); if (!config_password_cp1250) cp_to_iso((unsigned char *) p.password); if (p.status_descr) cp_to_iso((unsigned char *) p.status_descr); } /* * ekg_reconnect() * * jeśli jest włączony autoreconnect, wywołuje timer, który za podaną * ilość czasu spróbuje się połączyć jeszcze raz. */ void ekg_reconnect() { if (config_auto_reconnect && connecting) reconnect_timer = time(NULL); } /* * ekg_logoff() * * rozłącza się, zmieniając uprzednio stan na niedostępny z opisem. * * - sess - opis sesji, * - reason - powód, może być NULL. */ void ekg_logoff(struct gg_session *sess, const char *reason) { if (!sess) return; if (sess->state != GG_STATE_CONNECTED || GG_S_NA(sess->status)) return; if (reason) { char *tmp = xstrdup(reason); iso_to_cp((unsigned char *) tmp); gg_change_status_descr(sess, GG_STATUS_NOT_AVAIL_DESCR, tmp); xfree(tmp); } else gg_change_status(sess, GG_STATUS_NOT_AVAIL); gg_logoff(sess); update_status(); last_conn_event = time(NULL); } /* * ekg_hash() * * liczy prosty hash z nazwy, wykorzystywany przy przeszukiwaniu list * zmiennych, formatów itp. * * - name - nazwa. */ int ekg_hash(const char *name) { int hash = 0; for (; *name; name++) { hash ^= *name; hash <<= 1; } return hash; } /* * event_add() * * dodaje zdarzenie do listy zdarzeń. * * - flags, * - target, * - action, * - quiet. * * 0/-1 */ int event_add(int flags, const char *target, const char *action, int quiet) { int f; list_t l; struct event e; uin_t uin; struct userlist *u; char **arr = NULL; if (!target || !action) return -1; uin = str_to_uin(target); if ((u = userlist_find(uin, target))) uin = u->uin; for (l = events; l; l = l->next) { struct event *ev = l->data; if (ev->target[0] == '@') array_add(&arr, xstrdup(ev->target)); } for (l = events; l; l = l->next) { struct event *ev = l->data; int match = 0, i; if (target[0] == '@') { struct userlist *uu = userlist_find(str_to_uin(ev->target), ev->target); if (uu && group_member(uu, target + 1)) match = 1; } for (i = 0; arr && arr[i]; i++) { if (u && group_member(u, arr[i] + 1)) { match = 1; break; } } if (!strcasecmp(ev->target, target) || !strcmp(ev->target, itoa(uin)) || (u && u->display && !strcasecmp(ev->target, u->display))) match = 1; if (match && (f = ev->flags & flags)) { printq("events_exist", event_format(f), event_format_target(target)); array_free(arr); return -1; } } array_free(arr); for (f = 1; ; f++) { int taken = 0; for (l = events; l; l = l->next) { struct event *e = l->data; if (!strcmp(e->name, itoa(f))) { taken = 1; break; } } if (!taken) break; } e.name = xstrdup(itoa(f)); e.target = xstrdup(target); e.flags = flags; e.action = xstrdup(action); list_add(&events, &e, sizeof(e)); printq("events_add", e.name); return 0; } /* * event_remove() * * usuwa zdarzenie z listy zdarzeń. * * - name. * * 0/-1 */ int event_remove(const char *name, int quiet) { list_t l; int removed = 0, remove_all; if (!name) return -1; remove_all = !strcmp(name, "*"); for (l = events; l; ) { struct event *e = l->data; l = l->next; if (remove_all || (name && e->name && !strcasecmp(name, e->name))) { if (!remove_all) printq("events_del", name); xfree(e->action); xfree(e->target); xfree(e->name); list_remove(&events, e, 1); removed = 1; } } if (!removed) { if (remove_all) printq("events_list_empty"); else printq("events_del_noexist", name); return -1; } else { if (remove_all) printq("events_del_all"); else { int num = 1; for (l = events; l; l = l->next) { struct event *e = l->data; xfree(e->name); e->name = xstrdup(itoa(num++)); } } return 0; } } /* * event_format() * * zwraca łańcuch zdarzeń w oparciu o flagi. statyczny bufor. * * - flags. */ const char *event_format(int flags) { static char buf[200]; int i, first = 1; buf[0] = 0; if (flags == EVENT_ALL) return "*"; for (i = 0; event_labels[i].name; i++) { if ((flags & event_labels[i].event)) { if (!first) strlcat(buf, ",", sizeof(buf)); strlcat(buf, event_labels[i].name, sizeof(buf)); first = 0; } } return buf; } /* * event_format_target() * * zajmuje się sformatowaniem uina/aliasu w łańcuchu * znaków ze zdarzenia. nie zwalniać. */ const char *event_format_target(const char *target) { struct userlist *u; static char buf[200]; uin_t uin; if (!target) return ""; uin = str_to_uin(target); u = userlist_find(0, target); if (u) return format_user(u->uin); if (uin) return format_user(uin); else { strlcpy(buf, target, sizeof(buf)); return buf; } } /* * event_flags() * * zwraca flagi na podstawie łańcucha. * * - events. */ int event_flags(const char *events) { int i, j, flags = 0; char **a; if (!events) return flags; a = array_make(events, "|,:", 0, 1, 0); for (j = 0; a[j]; j++) { if (!strcmp(a[j], "*")) { flags = EVENT_ALL; break; } for (i = 0; event_labels[i].name; i++) if (!strcasecmp(a[j], event_labels[i].name)) flags |= event_labels[i].event; } array_free(a); return flags; } /* * event_check() * * sprawdza i ewentualnie uruchamia akcję na podane zdarzenie. * * - event, * - uin, * - data. * * 0/-1 */ int event_check(int event, uin_t uin, const char *data) { const char *uin_number = NULL, *uin_display = NULL; char *action = NULL, **actions, *edata = NULL; struct userlist *u; int i; list_t l; uin_number = itoa(uin); if ((u = userlist_find(uin, NULL)) && u->display) uin_display = u->display; else uin_display = uin_number; for (l = events; l; l = l->next) { struct event *e = l->data; if (e->flags & INACTIVE_EVENT) return 0; if (e->flags & event) { if (!strcmp(e->target, "*") || uin == 0) action = e->action; if (!strcmp(e->target, uin_number) || !strcasecmp(e->target, uin_display) || (u && group_member(u, e->target + 1))) { action = e->action; break; } } } if (!action) return -1; if (data) { int size = 1; const char *p; char *q; for (p = data; *p; p++) { if (strchr("`!#$&*?|\\\'\"{}[]<>()\n\r", *p)) size += 2; else size++; } edata = xmalloc(size); for (p = data, q = edata; *p; p++, q++) { if (strchr("`!#$&*?|\\\'\"{}[]<>()", *p)) *q++ = '\\'; if (*p == '\n') { *q++ = '\\'; *q = 'n'; continue; } if (*p == '\r') { *q++ = '\\'; *q = 'r'; continue; } *q = *p; } *q = 0; } actions = array_make(action, ";", 0, 0, 1); for (i = 0; actions && actions[i]; i++) { char *tmp = format_string(actions[i], uin_number, uin_display, ((data) ? data : ""), ((edata) ? edata : "")); gg_debug(GG_DEBUG_MISC, "// event_check() uin: %s event: \"%s\" doing: \"%s\"\n", uin_number, event_format(event), tmp); command_exec(NULL, tmp, 0); xfree(tmp); } array_free(actions); xfree(edata); return 0; } /* * event_free() * * zwalnia pamięć związaną ze zdarzeniami. */ void event_free() { list_t l; if (!events) return; for (l = events; l; l = l->next) { struct event *e = l->data; xfree(e->name); xfree(e->action); xfree(e->target); } list_destroy(events, 1); events = NULL; } /* * mesg_set() * * włącza/wyłącza/sprawdza możliwość pisania do naszego terminala. * * - what - MESG_ON, MESG_OFF lub MESG_CHECK * * -1 jeśli bład, lub aktualny stan: MESG_ON/MESG_OFF */ int mesg_set(int what) { const char *tty; struct stat s; if (!(tty = ttyname(old_stderr)) || stat(tty, &s)) { gg_debug(GG_DEBUG_MISC, "// mesg_set() error: %s\n", strerror(errno)); return -1; } switch (what) { case MESG_OFF: chmod(tty, s.st_mode & ~S_IWGRP); break; case MESG_ON: chmod(tty, s.st_mode | S_IWGRP); break; case MESG_CHECK: return ((s.st_mode & S_IWGRP) ? MESG_ON : MESG_OFF); } return 0; } /* * msg_encrypt() * * jeśli można, podmienia wiadomość na wiadomość * zaszyfrowaną. */ int msg_encrypt(uin_t uin, unsigned char **msg) { #ifdef HAVE_OPENSSL if (config_encryption == 1 || config_encryption == 3) { unsigned char *res = (unsigned char *) sim_message_encrypt(*msg, uin); if (res) { int ret = 1; xfree(*msg); *msg = res; if (strlen((char *) *msg) > 1989) { (*msg)[1989] = 0; ret = 2; } gg_debug(GG_DEBUG_MISC, "// ekg: simlite encrypted: %s\n", res); return ret; } gg_debug(GG_DEBUG_MISC, "// ekg: simlite encryption failed: %s\n", sim_strerror(sim_errno)); return 0; } #endif return 0; } /* * charmap_prepare() * * przygotowuje mapę znaków do użycia w funkcji charmap_convert() zgodnie ze * wzorcem convtab. wzorzec musi mieć parzystą liczbę pozycji. * * - charmap - bufor do wypełnienia (musi mieć 256 bajtów), * - convtab - wzorzec konwersji (przykład w cp_to_iso()), * - convtab_sz - rozmiar wzoraca konwersji, * - def - czy przygotować domyślną mapę */ static void charmap_prepare(unsigned char *charmap, const unsigned char *convtab, size_t convtab_sz, int def) { size_t i; if (convtab_sz & 1) return; if (def) for (i = 0; i < 256; i++) charmap[i] = (unsigned char) i; for (i = 0; i < convtab_sz;) { unsigned char from, to; from = convtab[i++]; to = convtab[i++]; charmap[from] = to; } } /* * charmap_convert() * * konwertuje bufor zgodnie z podaną mapą konwersji. * * - charmap - mapa konwersji (256 bajtów), * - buf - bufor */ static void charmap_convert(const unsigned char *charmap, unsigned char *buf) { if (!buf) return; for (; *buf; buf++) *buf = charmap[*buf]; } /* * cp_to_iso() * * zamienia krzaczki pisane w cp1250 na iso-8859-2, przy okazji maskując * znaki, których nie da się wyświetlić, za wyjątkiem \r i \n, oraz * zamieniając tabulacje na spacje. * * - buf. */ void cp_to_iso(unsigned char *buf) { static unsigned char charmap[256]; static int valid = 0; if (!valid) { static const unsigned char conv[] = { 0x09, 0x20, /* \t */ 0x0A, 0x0A, /* \n */ 0x0D, 0x0D, /* \r */ 0xB9, 0xB1, /* ą */ 0x9C, 0xB6, /* ś */ 0x9F, 0xBC, /* ź */ 0xA5, 0xA1, /* Ą */ 0x8C, 0xA6, /* Ś */ 0x8F, 0xAC, /* Ź */ 0x9A, 0xB9, /* š */ 0x8A, 0xA9, /* Š */ 0x9E, 0xBE, /* ž */ 0x8E, 0xAE, /* Ž */ 0x9D, 0xBB, /* ť */ 0x8D, 0xAB, /* Ť */ 0xBE, 0xB5, /* ľ */ 0xBC, 0xA5, /* Ľ */ }; size_t i; for (i = 0; i < 0x20; i++) charmap[i] = '?'; for (i = 0x20; i < 0x80; i++) charmap[i] = (unsigned char) i; for (i = 0x80; i < 0xA0; i++) charmap[i] = '?'; for (i = 0xA0; i < 0x100; i++) charmap[i] = (unsigned char) i; charmap_prepare(charmap, conv, sizeof(conv), 0); valid = 1; } charmap_convert(charmap, buf); } static const unsigned short table_iso_8859_2[] = { '?', '?', '?', '?', '?', '?', '?', '?', /* 0x80 - */ '?', '?', '?', '?', '?', '?', '?', '?', /* - 0x8F */ '?', '?', '?', '?', '?', '?', '?', '?', /* 0x90 - */ '?', '?', '?', '?', '?', '?', '?', '?', /* - 0x9F */ 0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7, /* 0xA0 - */ 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b, /* - 0xAF */ 0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7, /* 0xB0 - */ 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* - 0xBF */ 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, /* 0xC0 - */ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e, /* - 0xCF */ 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, /* 0xD0 - */ 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df, /* - 0xDF */ 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, /* 0xE0 - */ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f, /* - 0xEF */ 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, /* 0xF0 - */ 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9 /* - 0xFF */ }; /* utf8_to_iso() && iso_to_utf8() based on ekg2's gg_locale_to_cp() && gg_cp_to_locale() */ /* some code based on libiconv utf8_mbtowc() && utf8_wctomb() from utf8.h under LGPL-2.1 */ static int utf8_helper(unsigned char *s, int n, unsigned short *ch) { unsigned char c = s[0]; if (c < 0x80) { *ch = c; return 1; } if (c < 0xc2) goto invalid; if (c < 0xe0) { if (n < 2) goto invalid; if (!((s[1] ^ 0x80) < 0x40)) goto invalid; *ch = ((unsigned short) (c & 0x1f) << 6) | (unsigned short) (s[1] ^ 0x80); return 2; } if (c < 0xf0) { if (n < 3) goto invalid; if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0))) goto invalid; *ch = ((unsigned short) (c & 0x0f) << 12) | ((unsigned short) (s[1] ^ 0x80) << 6) | (unsigned short) (s[2] ^ 0x80); return 3; } invalid: *ch = '?'; return 1; } /* * utf8_to_iso() * * konwertuje utf8 na iso, zwalnia podany bufor i zwraca nowy. */ char *utf8_to_iso(char *b) { unsigned char *buf = (unsigned char *) b; char *newbuf; int newlen = 0; int len; int i, j; if (!buf) return NULL; len = strlen(b); for (i = 0; i < len; newlen++) { unsigned short discard; i += utf8_helper(&buf[i], len - i, &discard); } newbuf = xmalloc(newlen+1); for (i = 0, j = 0; buf[i]; j++) { unsigned short znak; int k; i += utf8_helper(&buf[i], len - i, &znak); if (znak < 0x80) { newbuf[j] = znak; continue; } newbuf[j] = '?'; for (k = 0; k < (sizeof(table_iso_8859_2)/sizeof(table_iso_8859_2[0])); k++) { if (table_iso_8859_2[k] == znak) { newbuf[j] = (0x80 | k); break; } } } newbuf[j] = '\0'; xfree(buf); return newbuf; } /* * iso_to_utf8() * * konwertuje iso na utf8, zwalnia podany bufor i zwraca nowy. */ char *iso_to_utf8(char *b) { unsigned char *buf = (unsigned char *) b; char *newbuf; int newlen = 0; int i, j; if (!buf) return NULL; for (i = 0; buf[i]; i++) { unsigned short znak = (buf[i] < 0x80) ? buf[i] : table_iso_8859_2[buf[i]-0x80]; if (znak < 0x80) newlen += 1; else if (znak < 0x800) newlen += 2; else newlen += 3; } newbuf = xmalloc(newlen+1); for (i = 0, j = 0; buf[i]; i++) { unsigned short znak = (buf[i] < 0x80) ? buf[i] : table_iso_8859_2[buf[i]-0x80]; int count; if (znak < 0x80) count = 1; else if (znak < 0x800) count = 2; else count = 3; switch (count) { case 3: newbuf[j+2] = 0x80 | (znak & 0x3f); znak = znak >> 6; znak |= 0x800; case 2: newbuf[j+1] = 0x80 | (znak & 0x3f); znak = znak >> 6; znak |= 0xc0; case 1: newbuf[j] = znak; } j += count; } newbuf[j] = '\0'; xfree(buf); return newbuf; } /* * iso_to_cp() * * zamienia sensowny format kodowania polskich znaczków na bezsensowny. * * - buf. */ void iso_to_cp(unsigned char *buf) { static unsigned char charmap[256]; static int valid = 0; if (!valid) { static const unsigned char conv[] = { 0xB1, 0xB9, /* ą */ 0xB6, 0x9C, /* ś */ 0xBC, 0x9F, /* ź */ 0xA1, 0xA5, /* Ą */ 0xA6, 0x8C, /* Ś */ 0xAC, 0x8F, /* Ź */ 0xB9, 0x9A, /* š */ 0xA9, 0x8A, /* Š */ 0xBE, 0x9E, /* ž */ 0xAE, 0x8E, /* Ž */ 0xBB, 0x9D, /* ť */ 0xAB, 0x8D, /* Ť */ 0xB5, 0xBE, /* ľ */ 0xA5, 0xBC, /* Ľ */ }; charmap_prepare(charmap, conv, sizeof(conv), 1); valid = 1; } charmap_convert(charmap, buf); } /* * iso_to_ascii() * * usuwa polskie litery z tekstu. * * - buf. */ void iso_to_ascii(unsigned char *buf) { static unsigned char charmap[256]; static int valid = 0; if (!valid) { static const unsigned char conv[] = { 'ę', 'e', 'ó', 'o', 'ą', 'a', 'ś', 's', 'ł', 'l', 'ż', 'z', 'ź', 'z', 'ć', 'c', 'ń', 'n', 'Ę', 'E', 'Ó', 'O', 'Ą', 'A', 'Ś', 'S', 'Ł', 'L', 'Ż', 'Z', 'Ź', 'Z', 'Ć', 'C', 'Ń', 'N' }; charmap_prepare(charmap, conv, sizeof(conv), 1); valid = 1; } charmap_convert(charmap, buf); } /* * strip_chars() * * pozbywa się podanego znaku na początku i końcu łancucha. */ char *strip_chars(char *line, unsigned char what) { while (*line == what) line++; while (strlen(line) > 1 && line[strlen(line) - 1] == what) line[strlen(line) - 1] = 0; return line; } /* * strip_spaces() * * pozbywa się spacji na początku i końcu łańcucha. */ char *strip_spaces(char *line) { return strip_chars(line, ' '); } /* * play_sound() * * odtwarza dzwięk o podanej nazwie. * * 0/-1 */ int play_sound(const char *sound_path) { char *params[2]; int res; if (!config_sound_app || !sound_path) { errno = EINVAL; return -1; } params[0] = saprintf("%s %s", config_sound_app, sound_path); params[1] = NULL; res = cmd_exec("exec", (const char**) params, NULL, 1); xfree(params[0]); return res; } /* * process_add() * * dopisuje do listy uruchomionych dzieci procesów. * * - pid. * - name. * * 0/-1 */ int process_add(int pid, const char *name) { struct process p; p.pid = pid; p.name = xstrdup(name); p.died = 0; return (list_add(&children, &p, sizeof(p)) ? 0 : -1); } /* * process_remove() * * usuwa proces z listy dzieciaków. * * - pid. * * 0/-1 */ int process_remove(int pid) { list_t l; for (l = children; l; l = l->next) { struct process *p = l->data; if (p->pid == pid) { xfree(p->name); list_remove(&children, p, 1); return 0; } } return -1; } /* * prepare_path() * * zwraca pełną ścieżkę do podanego pliku katalogu ~/.gg/ * * - filename - nazwa pliku, * - do_mkdir - czy tworzyć katalog ~/.gg ? */ const char *prepare_path(const char *filename, int do_mkdir) { static char path[PATH_MAX + 1]; if (do_mkdir) { if (config_profile) { char *cd = xstrdup(config_dir); if (mkdir(dirname(cd), 0700) && errno != EEXIST) { xfree(cd); return NULL; } xfree(cd); } if (mkdir(config_dir, 0700) && errno != EEXIST) return NULL; } if (!filename || !*filename) snprintf(path, sizeof(path), "%s", config_dir); else snprintf(path, sizeof(path), "%s/%s", config_dir, filename); return path; } char *random_line(const char *path) { int max = 0, item, tmp = 0; char *line; FILE *f; if (!path) return NULL; if ((f = fopen(path, "r")) == NULL) return NULL; while ((line = read_file(f))) { xfree(line); max++; } rewind(f); if (max) { item = rand() / (RAND_MAX / max + 1); while ((line = read_file(f))) { if (tmp == item) { fclose(f); return line; } xfree(line); tmp++; } } fclose(f); return NULL; } /* * read_file() * * czyta i zwraca linijkę tekstu z pliku, alokując przy tym odpowiedni buforek. * usuwa znaki końca linii. */ char *read_file(FILE *f) { char buf[1024], *res = NULL; while (fgets(buf, sizeof(buf), f)) { int first = (res) ? 0 : 1; size_t new_size = ((res) ? strlen(res) : 0) + strlen(buf) + 1; res = xrealloc(res, new_size); if (first) *res = 0; strlcpy(res + strlen(res), buf, new_size - strlen(res)); if (strchr(buf, '\n')) break; } if (res && strlen(res) > 0 && res[strlen(res) - 1] == '\n') res[strlen(res) - 1] = 0; if (res && strlen(res) > 0 && res[strlen(res) - 1] == '\r') res[strlen(res) - 1] = 0; return res; } /* * send_sms() * * wysyła sms o podanej treści do podanej osoby. * * 0/-1 */ int send_sms(const char *recipient, const char *message, int quiet) { int pid, fd[2] = { 0, 0 }; struct gg_exec s; char *tmp; if (!config_sms_app) { errno = EINVAL; return -1; } if (!recipient || !message) { errno = EINVAL; return -1; } if (pipe(fd)) return -1; if (!(pid = fork())) { dup2(open("/dev/null", O_RDONLY), 0); if (fd[1]) { close(fd[0]); dup2(fd[1], 2); dup2(fd[1], 1); close(fd[1]); } execlp(config_sms_app, config_sms_app, recipient, message, (void *) NULL); exit(1); } if (pid < 0) { close(fd[0]); close(fd[1]); return -1; } memset(&s, 0, sizeof(s)); s.fd = fd[0]; s.check = GG_CHECK_READ; s.state = GG_STATE_READING_DATA; s.type = GG_SESSION_USER3; s.id = pid; s.timeout = -1; s.buf = string_init(NULL); fcntl(s.fd, F_SETFL, O_NONBLOCK); list_add(&watches, &s, sizeof(s)); close(fd[1]); tmp = saprintf(((quiet) ? "\002%s" : "\001%s"), recipient); process_add(pid, tmp); xfree(tmp); return 0; } /* * sms_away_add() * * dodaje osobę do listy delikwentów, od których wiadomość wysłano sms'em * podczas naszej nieobecności. jeśli jest już na liście, to zwiększa * przyporządkowany mu licznik. * * - uin. */ void sms_away_add(uin_t uin) { struct sms_away sa; list_t l; if (!config_sms_away_limit) return; sa.uin = uin; sa.count = 1; for (l = sms_away; l; l = l->next) { struct sms_away *s = l->data; if (s->uin == uin) { s->count += 1; return; } } list_add(&sms_away, &sa, sizeof(sa)); } /* * sms_away_check() * * sprawdza czy wiadomość od danej osoby może zostać przekazana * na sms podczas naszej nieobecności, czy też może przekroczono * już limit. * * - uin * * 1 jeśli tak, 0 jeśli nie. */ int sms_away_check(uin_t uin) { int x = 0; list_t l; if (!config_sms_away_limit || !sms_away) return 1; /* limit dotyczy łącznej liczby sms'ów */ if (config_sms_away == 1) { for (l = sms_away; l; l = l->next) { struct sms_away *s = l->data; x += s->count; } if (x > config_sms_away_limit) return 0; else return 1; } /* limit dotyczy liczby sms'ów od jednej osoby */ for (l = sms_away; l; l = l->next) { struct sms_away *s = l->data; if (s->uin == uin) { if (s->count > config_sms_away_limit) return 0; else return 1; } } return 1; } /* * sms_away_free() * * zwalnia pamięć po liście ,,sms_away'' */ void sms_away_free() { if (!sms_away) return; list_destroy(sms_away, 1); sms_away = NULL; } #ifdef WITH_IOCTLD /* * ioctld_parse_seq() * * zamień string na odpowiednią strukturę dla ioctld. * * - seq, * - data. * * 0/-1. */ int ioctld_parse_seq(const char *seq, struct action_data *data) { char **entries; int i; if (!data || !seq) return -1; memset(data, -1, sizeof(struct action_data)); entries = array_make(seq, ",", 0, 0, 1); for (i = 0; entries[i] && i < IOCTLD_MAX_ITEMS; i++) { int delay; char *tmp; if ((tmp = strchr(entries[i], '/'))) { *tmp = 0; delay = atoi(tmp + 1); } else delay = IOCTLD_DEFAULT_DELAY; data->value[i] = atoi(entries[i]); data->delay[i] = delay; } array_free(entries); return 0; } /* * ioctld_socket() * * inicjuje gniazdo dla ioctld. * * - path - ścieżka do gniazda. * * 0/-1. */ int ioctld_socket(const char *path) { struct sockaddr_un sockun; int i, usecs = 50000; if (ioctld_sock != -1) close(ioctld_sock); if ((ioctld_sock = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) return -1; sockun.sun_family = AF_UNIX; strlcpy(sockun.sun_path, path, sizeof(sockun.sun_path)); for (i = 5; i; i--) { if (connect(ioctld_sock, (struct sockaddr*) &sockun, sizeof(sockun)) != -1) return 0; usleep(usecs); } close(ioctld_sock); ioctld_sock = -1; return -1; } /* * ioctld_send() * * wysyła do ioctld polecenie uruchomienia danej akcji. * * - seq - sekwencja danych, * - act - rodzaj akcji. * * 0/-1. */ int ioctld_send(const char *seq, int act, int quiet) { struct action_data data; if (*seq == '$') /* dla kompatybilności ze starym zachowaniem */ seq++; if (!xisdigit(*seq)) { const char *tmp = format_find(seq); if (!strcmp(tmp, "")) { printq("events_seq_not_found", seq); return -1; } seq = tmp; } if (ioctld_parse_seq(seq, &data)) { printq("events_seq_incorrect", seq); return -1; } data.act = act; return send(ioctld_sock, &data, sizeof(data), 0); } #endif /* WITH_IOCTLD */ /* * init_control_pipe() * * inicjuje potok nazwany do zewnętrznej kontroli ekg. * * - pipe_file. * * zwraca deskryptor otwartego potoku lub -1. */ int init_control_pipe(const char *pipe_file) { int fd; struct stat st; char *err_str = NULL; if (!pipe_file) return 0; if (!stat(pipe_file, &st) && !S_ISFIFO(st.st_mode)) err_str = saprintf("Plik %s nie jest potokiem. Ignoruję.\n", pipe_file); if (mkfifo(pipe_file, config_files_mode_config) < 0 && errno != EEXIST) err_str = saprintf("Nie mogę stworzyć potoku %s: %s. Ignoruję.\n", pipe_file, strerror(errno)); if ((fd = open(pipe_file, O_RDWR | O_NONBLOCK)) < 0) err_str = saprintf("Nie mogę otworzyć potoku %s: %s. Ignoruję.\n", pipe_file, strerror(errno)); if (err_str) { print("generic_error", err_str); xfree(err_str); return -1; } return fd; } /* * timestamp() * * zwraca statyczny buforek z ładnie sformatowanym czasem. * * - format. */ const char *timestamp(const char *format) { static char buf[100]; time_t t; struct tm *tm; time(&t); tm = localtime(&t); strftime(buf, sizeof(buf), format, tm); return buf; } /* * timestamp_time() * * jak wyzej, ale na podstawie podanego czasu. * * - format * - czas */ const char *timestamp_time(const char *format, time_t t) { struct tm *tm; static char buf[100]; if (!format || format[0] == '\0') return itoa(t); tm = localtime(&t); if (!strftime(buf, sizeof(buf), format, tm)) return "TOOLONG"; return buf; } /* * unidle() * * uaktualnia licznik czasu ostatniej akcji, żeby przypadkiem nie zrobiło * autoawaya, kiedy piszemy. */ void unidle() { time(&last_action); } /* * transfer_id() * * zwraca pierwszy wolny identyfikator transferu dcc. */ int transfer_id() { list_t l; int id = 1; for (l = transfers; l; l = l->next) { struct transfer *t = l->data; if (t->id >= id) id = t->id + 1; } return id; } /* * on_off() * * zwraca 1 jeśli tekst znaczy włączyć, 0 jeśli wyłączyć, -1 jeśli co innego. * * - value. */ int on_off(const char *value) { if (!value) return -1; if (!strcasecmp(value, "on") || !strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "tak") || !strcmp(value, "1")) return 1; if (!strcasecmp(value, "off") || !strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "nie") || !strcmp(value, "0")) return 0; return -1; } /* * timer_add() * * dodaje timera. * * - period - za jaki czas w sekundach ma być uruchomiony, * - persistent - czy stały timer, * - type - rodzaj timera, * - at - zwykły timer czy at? * - name - nazwa timera w celach identyfikacji. jeśli jest równa NULL, * zostanie przyznany pierwszy numerek z brzegu. * - command - komenda wywoływana po upłynięciu czasu. * * zwraca zaalokowaną struct timer lub NULL. */ struct timer *timer_add(time_t period, int persistent, int type, int at, const char *name, const char *command) { struct timer t; struct timeval tv; struct timezone tz; if (!name) { int i; for (i = 1; ; i++) { int gotit = 0; list_t l; for (l = timers; l; l = l->next) { struct timer *tt = l->data; if (!strcmp(tt->name, itoa(i))) { gotit = 1; break; } } if (!gotit) break; } name = itoa(i); } memset(&t, 0, sizeof(t)); gettimeofday(&tv, &tz); tv.tv_sec += period; memcpy(&t.ends, &tv, sizeof(tv)); t.period = period; t.name = xstrdup(name); t.command = xstrdup(command); t.type = type; t.at = at; t.persistent = persistent; return list_add(&timers, &t, sizeof(t)); } /* * timer_remove() * * usuwa timer. * * - name - nazwa timera, może być NULL, * - at - zwykły timer czy at? * - command - komenda timera, może być NULL. * * 0/-1 */ int timer_remove(const char *name, int at, const char *command) { list_t l; int removed = 0; for (l = timers; l; ) { struct timer *t = l->data; l = l->next; if ((at == t->at) && ((name && !strcasecmp(name, t->name)) || (command && !strcasecmp(command, t->command)))) { xfree(t->name); xfree(t->command); xfree(t->id); list_remove(&timers, t, 1); removed = 1; } } return ((removed) ? 0 : -1); } /* * timer_remove_user() * * usuwa wszystkie timery użytkownika. * * - at - czy to at? nie ma znaczenia, jeśli równe -1 * * 0/-1 */ int timer_remove_user(int at) { list_t l; int removed = 0; for (l = timers; l; ) { struct timer *t = l->data; l = l->next; if (t->type == TIMER_COMMAND && (at == -1 || at == t->at)) { xfree(t->name); xfree(t->command); xfree(t->id); list_remove(&timers, t, 1); removed = 1; } } return ((removed) ? 0 : -1); } /* * timer_free() * * zwalnia pamięć po timerach. */ void timer_free() { list_t l; for (l = timers; l; l = l->next) { struct timer *t = l->data; xfree(t->name); xfree(t->command); xfree(t->id); } list_destroy(timers, 1); timers = NULL; } /* * xstrmid() * * wycina fragment tekstu alokując dla niego pamięć. * * - str - tekst źródłowy, * - start - pierwszy znak, * - length - długość wycinanego tekstu, jeśli -1 do końca. */ char *xstrmid(const char *str, int start, int length) { char *res, *q; const char *p; if (!str) return xstrdup(""); if (start > strlen(str)) start = strlen(str); if (length == -1) length = strlen(str) - start; if (length < 1) return xstrdup(""); if (length > strlen(str) - start) length = strlen(str) - start; res = xmalloc(length + 1); for (p = str + start, q = res; length; p++, q++, length--) *q = *p; *q = 0; return res; } /* * http_error_string() * * zwraca tekst opisujący powód błędu usług po http. * * - h - wartość gg_http->error lub 0, gdy funkcja zwróciła NULL. */ const char *http_error_string(int h) { switch (h) { case 0: return format_find((errno == ENOMEM) ? "http_failed_memory" : "http_failed_connecting"); case GG_ERROR_RESOLVING: return format_find("http_failed_resolving"); case GG_ERROR_CONNECTING: return format_find("http_failed_connecting"); case GG_ERROR_READING: return format_find("http_failed_reading"); case GG_ERROR_WRITING: return format_find("http_failed_writing"); } return "?"; } /* * update_status() * * uaktualnia własny stan w liście kontaktów, jeśli dopisaliśmy siebie. */ void update_status() { struct userlist *u = userlist_find(config_uin, NULL); if (!u) return; if ((u->descr && config_reason && strcmp(u->descr, config_reason)) || (!u->descr && config_reason) || (u->descr && !config_reason)) event_check(EVENT_DESCR, config_uin, config_reason); xfree(u->descr); u->descr = xstrdup(config_reason); if (ignored_check(u->uin) & IGNORE_STATUS) { u->status = GG_STATUS_NOT_AVAIL; return; } if (!sess || sess->state != GG_STATE_CONNECTED) u->status = (u->descr) ? GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL; else u->status = GG_S(config_status); if (ignored_check(u->uin) & IGNORE_STATUS_DESCR) u->status = ekg_hide_descr_status(u->status); } /* * update_status_myip() * * zajmuje się wpisaniem własnego adresu IP i portu na liście. */ void update_status_myip() { struct userlist *u = userlist_find(config_uin, NULL); if (!u) return; if (!sess || sess->state != GG_STATE_CONNECTED) goto fail; if (config_dcc && config_dcc_ip && config_dcc_port) { list_t l; if (strcmp(config_dcc_ip, "auto")) u->ip.s_addr = inet_addr(config_dcc_ip); else { struct sockaddr_in foo; socklen_t bar = sizeof(foo); if (getsockname(sess->fd, (struct sockaddr *) &foo, &bar)) goto fail; u->ip.s_addr = foo.sin_addr.s_addr; } u->port = 0; for (l = watches; l; l = l->next) { struct gg_dcc *d = l->data; if (d->type == GG_SESSION_DCC_SOCKET) { u->port = d->port; break; } } return; } fail: memset(&u->ip, 0, sizeof(struct in_addr)); u->port = 0; } /* * change_status() * * zmienia stan sesji. * * - status - nowy stan. wartość stanu libgadu, bez lub z _DESCR. * - reason - opis stanu, może być NULL. * - autom - czy zmiana jest automatyczna? */ void change_status(int status, const char *xarg, int autom) { const char *filename, *config_x_reason, *format, *format_descr, *auto_format = NULL, *auto_format_descr = NULL; int random_mask, status_descr; char *reason = NULL, *tmp = NULL, *arg; int private_mask = (GG_S_F(config_status) ? GG_STATUS_FRIENDS_MASK : 0); status = GG_S(status); arg = xstrdup(xarg); switch (status) { case GG_STATUS_BUSY: case GG_STATUS_BUSY_DESCR: status_descr = GG_STATUS_BUSY_DESCR; random_mask = 1; filename = "away.reasons"; config_x_reason = config_away_reason; format = "away"; format_descr = "away_descr"; auto_format = "auto_away"; auto_format_descr = "auto_away_descr"; break; case GG_STATUS_AVAIL: case GG_STATUS_AVAIL_DESCR: status_descr = GG_STATUS_AVAIL_DESCR; random_mask = 4; filename = "back.reasons"; config_x_reason = config_back_reason; format = "back"; format_descr = "back_descr"; auto_format = "auto_back"; auto_format_descr = "auto_back_descr"; break; case GG_STATUS_DND: case GG_STATUS_DND_DESCR: status_descr = GG_STATUS_DND_DESCR; random_mask = 4; filename = "dnd.reasons"; config_x_reason = config_dnd_reason; format = "dnd"; format_descr = "dnd_descr"; auto_format = "auto_dnd"; auto_format_descr = "auto_dnd_descr"; break; case GG_STATUS_FFC: case GG_STATUS_FFC_DESCR: status_descr = GG_STATUS_FFC_DESCR; random_mask = 4; filename = "ffc.reasons"; config_x_reason = config_ffc_reason; format = "ffc"; format_descr = "ffc_descr"; auto_format = "auto_ffc"; auto_format_descr = "auto_ffc_descr"; break; case GG_STATUS_INVISIBLE: case GG_STATUS_INVISIBLE_DESCR: status_descr = GG_STATUS_INVISIBLE_DESCR; random_mask = 8; filename = "quit.reasons"; config_x_reason = config_quit_reason; format = "invisible"; format_descr = "invisible_descr"; break; case GG_STATUS_NOT_AVAIL: case GG_STATUS_NOT_AVAIL_DESCR: status_descr = GG_STATUS_NOT_AVAIL_DESCR; random_mask = 8; filename = "quit.reasons"; config_x_reason = config_quit_reason; format = "invisible"; format_descr = "invisible_descr"; break; default: return; } #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(status_own, "(is)", status, arg) { char *a; PYTHON_HANDLE_RESULT("is", &status, &a) { xfree(arg); arg = xstrdup(a); } } PYTHON_HANDLE_FOOTER() if (!python_handle_result) { xfree(arg); return; } #endif if (!(config_auto_away % 60)) tmp = saprintf("%dm", config_auto_away / 60); else tmp = saprintf("%ds", config_auto_away); if (!arg) { if (config_random_reason & random_mask) { reason = random_line(prepare_path(filename, 0)); if (!reason && config_x_reason) reason = xstrdup(config_x_reason); } else if (config_x_reason) reason = xstrdup(config_x_reason); } else reason = xstrdup(arg); if (!reason && config_keep_reason && config_reason) reason = xstrdup(config_reason); if (arg && !strcmp(arg, "-")) { xfree(reason); reason = NULL; status = ekg_hide_descr_status(status); } if (reason) status = status_descr; if (reason) { char *r1, *r2; r1 = xstrmid(reason, 0, GG_STATUS_DESCR_MAXSIZE); r2 = xstrmid(reason, GG_STATUS_DESCR_MAXSIZE, -1); switch (autom) { case 0: print(format_descr, r1, r2); break; case 1: print(auto_format_descr, tmp, r1, r2); break; case 2: break; } xfree(reason); reason = r1; xfree(r2); } else { switch (autom) { case 0: print(format); break; case 1: print(auto_format, tmp); break; case 2: break; } } ui_event("my_status", (reason) ? format_descr : format, reason, NULL); ui_event("my_status_raw", status, reason, NULL); xfree(config_reason); config_reason = reason; config_status = status | private_mask; if (sess && sess->state == GG_STATE_CONNECTED) { if (config_reason) { iso_to_cp((unsigned char *) config_reason); gg_change_status_descr(sess, config_status, config_reason); cp_to_iso((unsigned char *) config_reason); } else gg_change_status(sess, config_status); } xfree(tmp); xfree(arg); update_status(); } /* * ekg_status_label() * * tworzy etykietę opisującą stan, z podanym prefiksem. * * - status, * - prefix. * * zwraca statyczny tekst. */ const char *ekg_status_label(int status, const char *prefix) { static char buf[100]; const char *label = "unknown"; switch (GG_S(status)) { case GG_STATUS_AVAIL: label = "avail"; break; case GG_STATUS_AVAIL_DESCR: label = "avail_descr"; break; case GG_STATUS_NOT_AVAIL: label = "not_avail"; break; case GG_STATUS_NOT_AVAIL_DESCR: label = "not_avail_descr"; break; case GG_STATUS_BUSY: label = "busy"; break; case GG_STATUS_BUSY_DESCR: label = "busy_descr"; break; case GG_STATUS_FFC: label = "ffc"; break; case GG_STATUS_FFC_DESCR: label = "ffc_descr"; break; case GG_STATUS_DND: label = "dnd"; break; case GG_STATUS_DND_DESCR: label = "dnd_descr"; break; case GG_STATUS_INVISIBLE: label = "invisible"; break; case GG_STATUS_INVISIBLE_DESCR: label = "invisible_descr"; break; case GG_STATUS_BLOCKED: label = "blocked"; break; } snprintf(buf, sizeof(buf), "%s%s", (prefix) ? prefix : "", label); return buf; } /* * ekg_hide_descr_status() * * jeśli dany status jest opisowy, zwraca * taki sam status bez opisu. */ int ekg_hide_descr_status(int status) { int ret = status, private_mask = (GG_S_F(status) ? GG_STATUS_FRIENDS_MASK : 0); switch (GG_S(status)) { case GG_STATUS_AVAIL_DESCR: ret = GG_STATUS_AVAIL; break; case GG_STATUS_BUSY_DESCR: ret = GG_STATUS_BUSY; break; case GG_STATUS_INVISIBLE_DESCR: ret = GG_STATUS_INVISIBLE; break; case GG_STATUS_NOT_AVAIL_DESCR: ret = GG_STATUS_NOT_AVAIL; break; } return (ret | private_mask); } struct color_map default_color_map[26] = { { 'k', 0, 0, 0 }, { 'r', 168, 0, 0, }, { 'g', 0, 168, 0, }, { 'y', 168, 168, 0, }, { 'b', 0, 0, 168, }, { 'm', 168, 0, 168, }, { 'c', 0, 168, 168, }, { 'w', 168, 168, 168, }, { 'K', 96, 96, 96 }, { 'R', 255, 0, 0, }, { 'G', 0, 255, 0, }, { 'Y', 255, 255, 0, }, { 'B', 0, 0, 255, }, { 'M', 255, 0, 255, }, { 'C', 0, 255, 255, }, { 'W', 255, 255, 255, }, /* dodatkowe mapowanie różnych kolorów istniejących w GG */ { 'C', 128, 255, 255, }, { 'G', 128, 255, 128, }, { 'M', 255, 128, 255, }, { 'B', 128, 128, 255, }, { 'R', 255, 128, 128, }, { 'Y', 255, 255, 128, }, { 'm', 168, 128, 168, }, { 'c', 128, 168, 168, }, { 'g', 64, 168, 64, }, { 'm', 128, 64, 128, } }; /* * color_map() * * funkcja zwracająca kod koloru z domyślnej 16-kolorowej palety terminali * ansi odpadającemu podanym wartościom RGB. */ char color_map(unsigned char r, unsigned char g, unsigned char b) { unsigned long mindist = 255 * 255 * 255; struct color_map *map = default_color_map; char ch = 0; int i; /* gg_debug(GG_DEBUG_MISC, "color=%.2x%.2x%.2x\n", r, g, b); */ #define __sq(x) ((x)*(x)) for (i = 0; i < 26; i++) { unsigned long dist = __sq(r - map[i].r) + __sq(g - map[i].g) + __sq(b - map[i].b); /* gg_debug(GG_DEBUG_MISC, "%d(%c)=%.2x%.2x%.2x, dist=%ld\n", i, map[i].color, map[i].r, map[i].g, map[i].b, dist); */ if (dist < mindist) { ch = map[i].color; mindist = dist; } } #undef __sq /* gg_debug(GG_DEBUG_MISC, "mindist=%ld, color=%c\n", mindist, ch); */ return ch; } /* * strcasestr() * * robi to samo co strstr() tyle że bez zwracania uwagi na wielkość * znaków. */ char *strcasestr(const char *haystack, const char *needle) { int i, hlen = strlen(haystack), nlen = strlen(needle); for (i = 0; i <= hlen - nlen; i++) { if (!strncasecmp(haystack + i, needle, nlen)) return (char*) (haystack + i); } return NULL; } /* * say_it() * * zajmuje się wypowiadaniem tekstu, uważając na już działający * syntezator w tle. * * 0/-1/-2. -2 w przypadku, gdy dodano do bufora. */ int say_it(const char *str) { pid_t pid; if (!config_speech_app || !str || !strcmp(str, "")) return -1; if (speech_pid) { buffer_add(BUFFER_SPEECH, NULL, str, 50); return -2; } if ((pid = fork()) < 0) return -1; speech_pid = pid; if (!pid) { char *tmp = saprintf("%s 2>/dev/null 1>&2", config_speech_app); FILE *f = popen(tmp, "w"); int status = -1; xfree(tmp); if (f) { fprintf(f, "%s.", str); status = pclose(f); /* dzieciak czeka na dzieciaka */ } exit(status); } process_add(pid, "\003"); return 0; } /* * parsetimestr() * * przekształca zapis czasu w formacie [[[yyyy]mm]dd]HH[:]MM[.SS] * na ,,time_t''. zwraca -1 w przypadku błędu. */ time_t parsetimestr(const char *p) { struct tm *lt; time_t now = time(NULL); char *tmp, *foo = xstrdup(p); int wrong = 0; lt = localtime(&now); lt->tm_isdst = -1; /* wyciągamy sekundy, jeśli są i obcinamy */ if ((tmp = strchr(foo, '.')) && !(wrong = (strlen(tmp) < 2))) { sscanf(tmp + 1, "%2d", <->tm_sec); tmp[0] = 0; } else lt->tm_sec = 0; /* pozbądźmy się dwukropka */ if ((tmp = strchr(foo, ':')) && !(wrong = (strlen(tmp) != 3))) { tmp[0] = tmp[1]; tmp[1] = tmp[2]; tmp[2] = 0; } /* jedziemy ... */ if (!wrong) { switch (strlen(foo)) { int ret; case 12: ret = sscanf(foo, "%4d%2d%2d%2d%2d", <->tm_year, <->tm_mon, <->tm_mday, <->tm_hour, <->tm_min); if (ret != 5) wrong = 1; lt->tm_year -= 1900; lt->tm_mon -= 1; break; case 10: ret = sscanf(foo, "%2d%2d%2d%2d%2d", <->tm_year, <->tm_mon, <->tm_mday, <->tm_hour, <->tm_min); if (ret != 5) wrong = 1; lt->tm_year += 100; lt->tm_mon -= 1; break; case 8: ret = sscanf(foo, "%2d%2d%2d%2d", <->tm_mon, <->tm_mday, <->tm_hour, <->tm_min); if (ret != 4) wrong = 1; lt->tm_mon -= 1; break; case 6: ret = sscanf(foo, "%2d%2d%2d", <->tm_mday, <->tm_hour, <->tm_min); if (ret != 3) wrong = 1; break; case 4: ret = sscanf(foo, "%2d%2d", <->tm_hour, <->tm_min); if (ret != 2) wrong = 1; break; default: wrong = 1; } } xfree(foo); /* nie ma błędów ? */ if (wrong || lt->tm_hour > 23 || lt->tm_min > 59 || lt->tm_sec > 59 || lt->tm_mday > 31 || !lt->tm_mday || lt->tm_mon > 11) return -1; else return mktime(lt); } /* * unique_name() * * jeśli jest włączone config_dcc_backups, to tworzy unikalną ścieżkę * do pliku, dodając sufiksy od 1 do 1000. * * - path: ścieżka do zmiany * * zwraca: * - NULL: nie udało się utworzyć backupu * - path: backup nie był potrzebny lub config_dcc_backups == 0 * - pozostałe wartości: wskaźnik do nowej ścieżki */ unsigned char *unique_name(unsigned char *path) { struct stat st; int num; unsigned char *newpath = NULL; /* żeby nie było warninga */ if (!config_dcc_backups || stat((char *) path, &st)) return path; for (num = 1; num < 1000; num++) { newpath = (unsigned char *) saprintf("%s.%d", path, num); if (stat((char *) newpath, &st) == -1) break; xfree(newpath); } return (num == 1000) ? NULL : newpath; } /* * get_line() * * pobiera linię tekstu z bufora. funkcja niszczy bufor źródłowy * bezpowrotnie, dzieląc go na kolejne ciągi znaków i obcina znaki * końca linii. * * - ptr - wskaźnik do zmiennej, która przechowuje aktualne położenie * w analizowanym buforze. * * wskaźnik do kolejnej linii tekstu lub NULL, jeżeli to już koniec * bufora. */ char *get_line(char **ptr) { char *foo, *res; if (!ptr || !*ptr || !strcmp(*ptr, "")) return NULL; res = *ptr; if (!(foo = strchr(*ptr, '\n'))) *ptr += strlen(*ptr); else { size_t len; *ptr = foo + 1; *foo = 0; len = strlen(res); if (len > 1 && res[len - 1] == '\r') res[len - 1] = 0; } return res; } ekg-1.9~pre+r2855/src/stuff.h000066400000000000000000000326311174410337000157130ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2005 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Dawid Jarosz * Piotr Domagalski * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __STUFF_H #define __STUFF_H #include #include #include #include #include #include #include #include "dynstuff.h" #include "libgadu.h" #include "ioctld.h" #define DEBUG_MAX_LINES 50 /* ile linii z debug zrzucać do pliku */ #define TOGGLE_BIT(x) (1 << (x - 1)) #define SPYING_RESPONSE_TIMEOUT 15 enum event_t { EVENT_MSG = TOGGLE_BIT(1), EVENT_CHAT = TOGGLE_BIT(2), EVENT_CONFERENCE = TOGGLE_BIT(3), EVENT_QUERY = TOGGLE_BIT(4), EVENT_AVAIL = TOGGLE_BIT(5), EVENT_ONLINE = TOGGLE_BIT(6), EVENT_NOT_AVAIL = TOGGLE_BIT(7), EVENT_AWAY = TOGGLE_BIT(8), EVENT_INVISIBLE = TOGGLE_BIT(9), EVENT_DESCR = TOGGLE_BIT(10), EVENT_DCC = TOGGLE_BIT(11), EVENT_SIGUSR1 = TOGGLE_BIT(12), EVENT_SIGUSR2 = TOGGLE_BIT(13), EVENT_DELIVERED = TOGGLE_BIT(14), EVENT_QUEUED = TOGGLE_BIT(15), EVENT_FILTERED = TOGGLE_BIT(16), EVENT_MBOXFULL = TOGGLE_BIT(17), EVENT_NOT_DELIVERED = TOGGLE_BIT(18), EVENT_NEWMAIL = TOGGLE_BIT(19), EVENT_BLOCKED = TOGGLE_BIT(20), EVENT_DCCFINISH = TOGGLE_BIT(21), EVENT_CONNECTED = TOGGLE_BIT(22), EVENT_DISCONNECTED = TOGGLE_BIT(23), EVENT_CONNECTIONLOST = TOGGLE_BIT(24), EVENT_IMAGE = TOGGLE_BIT(25), EVENT_DND = TOGGLE_BIT(26), EVENT_FFC = TOGGLE_BIT(27), EVENT_ALL = TOGGLE_BIT(28) - 1, INACTIVE_EVENT = TOGGLE_BIT(28) }; struct event_label { int event; char *name; }; #define EVENT_LABELS_COUNT 25 /* uaktualnić ! */ struct event_label event_labels[EVENT_LABELS_COUNT + 2]; struct process { int pid; /* id procesu */ int died; /* proces umarł, ale najpierw pobieramy do końca z bufora dane */ char *name; /* nazwa. jeśli poprzedzona \2 to nie obchodzi */ /* nas w jaki sposób się zakończyło, \3 to samo, */ /* ale nie wyświetla na liście procesów */ }; struct alias { char *name; /* nazwa aliasu */ list_t commands; /* commands->data to (char*) */ }; struct transfer { uin_t uin; char *filename; struct gg_dcc *dcc; struct gg_dcc7 *dcc7; time_t start; int type; int id; int protocol; }; struct event { char *name; /* identyfikator */ char *target; /* uin, alias lub grupa */ int flags; /* flagi zdarzenia */ char *action; /* akcja! */ }; struct binding { char *key; char *action; /* akcja */ int internal; /* czy domyślna kombinacja? */ void (*function)(const char *arg); /* funkcja obsługująca */ char *arg; /* argument funkcji */ char *default_action; /* domyślna akcja */ void (*default_function)(const char *arg); /* domyślna funkcja */ char *default_arg; /* domyślny argument */ }; enum mesg_t { MESG_CHECK = -1, MESG_OFF, MESG_ON, MESG_DEFAULT }; enum timer_t { TIMER_SCRIPT, TIMER_UI, TIMER_COMMAND }; struct timer { struct timeval ends; /* kiedy się kończy? */ time_t period; /* ile sekund ma trwać czekanie */ int persistent; /* czy ma być na zawsze? */ int type; /* rodzaj timera */ int at; /* at czy zwykły timer? */ char *name; /* nazwa timera */ char *command; /* komenda do wywołania */ char *id; }; struct spied { uin_t uin; int timeout; struct timeval request_sent; }; struct sms_away { uin_t uin; int count; }; struct conference { char *name; int ignore; list_t recipients; }; struct gg_exec { gg_common_head(struct gg_exec) int msg; /* czy wysyłamy stdout komuś? 1 - tak, 2 - tak, buforujemy */ string_t buf; /* bufor na stdout procesu */ char *target; /* okno, do którego ma lecieć wynik */ int quiet; /* czy być cicho ? */ }; enum buffer_t { BUFFER_DEBUG, /* na zapisanie n ostatnich linii debug */ BUFFER_EXEC, /* na buforowanie tego, co wypluwa exec */ BUFFER_SPEECH /* na wymawiany tekst */ }; struct buffer { int type; char *target; char *line; }; struct color_map { int color; unsigned char r, g, b; }; list_t autofinds; list_t children; list_t aliases; list_t watches; list_t transfers; list_t events; list_t bindings; list_t timers; list_t conferences; list_t sms_away; list_t buffers; list_t searches; list_t spiedlist; struct gg_session *sess; time_t last_save; char *config_profile; int config_changed; pid_t speech_pid; int old_stderr; int mesg_startup; char *config_audio_device; char *config_away_reason; int config_auto_away; int config_auto_away_keep_descr; int config_auto_back; int config_auto_find; int config_auto_conference; int config_auto_reconnect; int config_auto_save; #ifdef WITH_ASPELL int config_aspell; char *config_aspell_lang; char *config_aspell_encoding; #endif char *config_back_reason; char *config_ffc_reason; char *config_dnd_reason; int config_beep; int config_beep_msg; int config_beep_chat; int config_beep_notify; int config_beep_mail; int config_check_mail; int config_check_mail_frequency; char *config_check_mail_folders; int config_completion_notify; int config_contacts; char *config_contacts_groups; char *config_contacts_options; int config_contacts_size; int config_ctrld_quits; int config_dcc; int config_dcc_backups; char *config_dcc_ip; char *config_dcc_dir; int config_dcc_filter; char *config_dcc_limit; int config_dcc_port; int config_display_ack; int config_display_color; char *config_display_color_map; int config_display_crap; int config_display_daychanges; int config_display_notify; int config_display_pl_chars; int config_display_sent; #if defined HAVE_LIBJPEG || defined HAVE_LIBUNGIF int config_display_token; #endif int config_display_welcome; int config_display_transparent; char *config_email; int config_emoticons; int config_encryption; int config_enter_scrolls; int config_events_delay; int config_files_mode_config; int config_files_mode_received; int config_files_mode_config_int; int config_files_mode_received_int; char *config_interface; int config_header_size; int config_ignore_unknown_sender; int config_ignore_empty_msg; int config_irssi_set_mode; int config_keep_reason; int config_last; int config_last_size; int config_last_sysmsg; int config_last_sysmsg_changed; char *config_local_ip; int config_log; int config_log_ignored; char *config_log_path; int config_log_status; char *config_log_timestamp; int config_make_window; int config_msg_as_chat; int config_mesg; #ifdef WITH_UI_NCURSES int config_mouse; #endif char *config_nick; char *config_password; int config_password_cp1250; int config_protocol; char *config_proxy; char *config_proxy_forwarding; int config_query_commands; char *config_quit_reason; int config_random_reason; #ifdef HAVE_REGEX_H int config_regex_flags; #endif char *config_reason; int config_reason_limit; int config_receive_images; int config_image_size; int config_save_question; int config_save_password; char *config_server; int config_server_save; int config_slash_messages; char *config_sms_app; int config_sms_away; int config_sms_away_limit; int config_sms_max_length; char *config_sms_number; int config_sort_windows; char *config_sound_app; char *config_sound_chat_file; char *config_sound_msg_file; char *config_sound_sysmsg_file; char *config_sound_notify_file; char *config_sound_mail_file; char *config_speech_app; int config_status; int config_status_window; int config_statusbar_size; int config_statusbar_fgcolor; int config_statusbar_bgcolor; char *config_tab_command; char *config_theme; int config_time_deviation; char *config_datestamp; char *config_timestamp; int config_uin; int config_userlist_backup; char *config_windows_layout; int config_windows_save; #ifdef WITH_WAP int config_wap_enabled; #endif #ifdef WITH_IOCTLD int config_ioctld_enable; int config_ioctld_net_port; #endif char *home_dir; char *config_dir; int command_processing; int in_autoexec; int no_autorun; int reconnect_timer; time_t last_action; int connecting; time_t last_conn_event; time_t ekg_started; int server_index; int in_auto_away; int quit_command; int use_proxy; int proxy_port; char *proxy_host; char *reg_password; char *reg_email; int quit_message_send; int registered_today; int pipe_fd; int batch_mode; char *batch_line; int ioctld_sock; struct color_map default_color_map[16+10]; char *last_search_first_name; char *last_search_last_name; char *last_search_nickname; uin_t last_search_uin; char *last_tokenid; int strcoll_usable; int alias_add(const char *string, int quiet, int append); int alias_remove(const char *name, int quiet); void alias_free(void); char *base64_encode(const char *buf); char *base64_decode(const char *buf); void binding_list(int quiet, const char *name, int all); void binding_free(void); int buffer_add(int type, const char *target, const char *line, int max_lines); int buffer_count(int type); char *buffer_flush(int type, const char *target); char *buffer_tail(int type); void buffer_free(void); void changed_auto_save(const char *var); #ifdef WITH_ASPELL void changed_aspell(const char *var); #endif void changed_backlog_size(const char *var); void changed_dcc(const char *var); void changed_local_ip(const char *var); void changed_mesg(const char *var); void changed_proxy(const char *var); void changed_theme(const char *var); void changed_uin(const char *var); void changed_xxx_reason(const char *var); void changed_files_mode(const char *var); struct conference *conference_add(const char *string, const char *nicklist, int quiet); int conference_remove(const char *name, int quiet); struct conference *conference_create(const char *nicks); struct conference *conference_find(const char *name); struct conference *conference_find_by_uins(uin_t from, uin_t *recipients, int count, int quiet); int conference_set_ignore(const char *name, int flag, int quiet); int conference_rename(const char *oldname, const char *newname, int quiet); int conference_participant(struct conference *c, uin_t uin); void conference_free(void); void ekg_connect(void); void ekg_reconnect(void); void ekg_logoff(struct gg_session *sess, const char *reason); int ekg_hash(const char *name); int event_add(int flags, const char *target, const char *action, int quiet); int event_remove(const char *name, int quiet); const char *event_format(int flags); const char *event_format_target(const char *target); int event_flags(const char *events); int event_check(int event, uin_t uin, const char *data); void event_free(void); int mesg_set(int what); int msg_encrypt(uin_t uin, unsigned char **msg); void cp_to_iso(unsigned char *buf); char *utf8_to_iso(char *buf); void iso_to_cp(unsigned char *buf); void iso_to_ascii(unsigned char *buf); char *iso_to_utf8(char *buf); char *strip_chars(char *line, unsigned char what); char *strip_spaces(char *line); int play_sound(const char *sound_path); int process_add(int pid, const char *name); int process_remove(int pid); const char *prepare_path(const char *filename, int do_mkdir); char *random_line(const char *path); char *read_file(FILE *f); int send_sms(const char *recipient, const char *message, int quiet); void sms_away_add(uin_t uin); int sms_away_check(uin_t uin); void sms_away_free(void); int ioctld_socket(const char *path); int ioctld_send(const char *seq, int act, int quiet); int init_control_pipe(const char *path); const char *timestamp(const char *format); const char *timestamp_time(const char *format, time_t t); void unidle(void); int on_off(const char *value); int transfer_id(void); char *xstrmid(const char *str, int start, int length); const char *http_error_string(int h); char color_map(unsigned char r, unsigned char g, unsigned char b); char *strcasestr(const char *haystack, const char *needle); int say_it(const char *str); time_t parsetimestr(const char *p); /* makra, dzięki którym pozbywamy się warning'ów */ #define xisxdigit(c) isxdigit((int) (unsigned char) c) #define xisdigit(c) isdigit((int) (unsigned char) c) #define xisalpha(c) isalpha((int) (unsigned char) c) #define xisalnum(c) isalnum((int) (unsigned char) c) #define xisspace(c) isspace((int) (unsigned char) c) #define xtolower(c) tolower((int) (unsigned char) c) #define xtoupper(c) toupper((int) (unsigned char) c) struct timer *timer_add(time_t period, int persistent, int type, int at, const char *name, const char *command); int timer_remove(const char *name, int at, const char *command); int timer_remove_user(int at); void timer_free(void); void update_status(void); void update_status_myip(void); void change_status(int status, const char *arg, int autom); const char *ekg_status_label(int status, const char *prefix); int ekg_hide_descr_status(int status); unsigned char *unique_name(unsigned char *path); char *get_line(char **ptr); /* funkcje poza stuff.c */ void ekg_wait_for_key(void); void ekg_exit(void); int check_conn(uin_t uin); void save_windows(void); #ifdef WITH_ASPELL void spellcheck_init(void); void spellcheck_deinit(void); #endif #endif /* __STUFF_H */ ekg-1.9~pre+r2855/src/themes.c000066400000000000000000001660271174410337000160530ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2007 Wojtek Kaniewski * Piotr Kupisiewicz * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include "dynstuff.h" #include "stuff.h" #include "themes.h" #include "xmalloc.h" #include "ui.h" #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif char *prompt_cache = NULL, *prompt2_cache = NULL, *error_cache = NULL; const char *timestamp_cache = NULL; int no_prompt_cache = 0; list_t formats = NULL; /* * format_find() * * odnajduje wartość danego formatu. jeśli nie znajdzie, zwraca pusty ciąg, * żeby nie musieć uważać na żadne null-references. * * - name. */ const char *format_find(const char *name) { const char *tmp; int hash; list_t l; if (!name) return ""; hash = ekg_hash(name); if (config_speech_app && !strchr(name, ',')) { char *name2 = saprintf("%s,speech", name); const char *tmp; if (strcmp((tmp = format_find(name2)), "")) { xfree(name2); return tmp; } xfree(name2); } if (config_theme && (tmp = strchr(config_theme, ',')) && !strchr(name, ',')) { char *name2 = saprintf("%s,%s", name, tmp + 1); const char *tmp; if (strcmp((tmp = format_find(name2)), "")) { xfree(name2); return tmp; } xfree(name2); } for (l = formats; l; l = l->next) { struct format *f = l->data; if (hash == f->name_hash && !strcasecmp(f->name, name)) return f->value; } return ""; } /* * format_ansi() * * zwraca sekwencję ansi odpowiadającą danemu kolorkowi z thememów ekg. */ const char *format_ansi(char ch) { if (ch == 'k') return "\033[0;30m"; if (ch == 'K') return "\033[1;30m"; if (ch == 'l') return "\033[40m"; if (ch == 'r') return "\033[0;31m"; if (ch == 'R') return "\033[1;31m"; if (ch == 's') return "\033[41m"; if (ch == 'g') return "\033[0;32m"; if (ch == 'G') return "\033[1;32m"; if (ch == 'h') return "\033[42m"; if (ch == 'y') return "\033[0;33m"; if (ch == 'Y') return "\033[1;33m"; if (ch == 'z') return "\033[43m"; if (ch == 'b') return "\033[0;34m"; if (ch == 'B') return "\033[1;34m"; if (ch == 'e') return "\033[44m"; if (ch == 'm' || ch == 'p') return "\033[0;35m"; if (ch == 'M' || ch == 'P') return "\033[1;35m"; if (ch == 'q') return "\033[45m"; if (ch == 'c') return "\033[0;36m"; if (ch == 'C') return "\033[1;36m"; if (ch == 'd') return "\033[46m"; if (ch == 'w') return "\033[0;37m"; if (ch == 'W') return "\033[1;37m"; if (ch == 'x') return "\033[47m"; if (ch == 'i') return "\033[5m"; if (ch == 'n') return "\033[0m"; if (ch == 'T') return "\033[1m"; return ""; } /* * va_format_string() * * formatuje zgodnie z podanymi parametrami ciąg znaków. * * - format - wartość, nie nazwa formatu, * - ap - argumenty. */ char *va_format_string(const char *format, va_list ap) { static int dont_resolve = 0; string_t buf = string_init(NULL); const char *p, *args[9]; int i, argc = 0; /* liczymy ilość argumentów */ for (p = format; *p; p++) { if (*p != '%') continue; p++; if (!*p) break; if (*p == '@') { p++; if (!*p) break; if ((*p - '0') > argc) argc = *p - '0'; } else if (*p == '(' || *p == '[') { if (*p == '(') { while (*p && *p != ')') p++; } else { while (*p && *p != ']') p++; } if (*p) p++; if (!*p) break; if ((*p - '0') > argc) argc = *p - '0'; } else { if (*p >= '1' && *p <= '9' && (*p - '0') > argc) argc = *p - '0'; } } for (i = 0; i < 9; i++) args[i] = NULL; for (i = 0; i < argc; i++) args[i] = va_arg(ap, char*); if (!dont_resolve) { dont_resolve = 1; if (no_prompt_cache) { /* zawsze czytaj */ timestamp_cache = format_find("timestamp"); prompt_cache = format_string(format_find("prompt")); prompt2_cache = format_string(format_find("prompt2")); error_cache = format_string(format_find("error")); } else { /* tylko jeśli nie są keszowanie */ if (!timestamp_cache) timestamp_cache = format_find("timestamp"); if (!prompt_cache) prompt_cache = format_string(format_find("prompt")); if (!prompt2_cache) prompt2_cache = format_string(format_find("prompt2")); if (!error_cache) error_cache = format_string(format_find("error")); } dont_resolve = 0; } p = format; while (*p) { if (*p == '%') { int fill_before, fill_after, fill_soft, fill_length; char fill_char; p++; if (!*p) break; if (*p == '%') string_append_c(buf, '%'); if (*p == '>') string_append(buf, prompt_cache); if (*p == ')') string_append(buf, prompt2_cache); if (*p == '!') string_append(buf, error_cache); if (*p == '|') string_append(buf, "\033[00m"); /* głupie, wiem */ if (*p == ']') string_append(buf, "\033[000m"); /* jeszcze głupsze */ if (*p == '#') string_append(buf, timestamp(timestamp_cache)); else if (config_display_color) { string_append(buf, format_ansi(*p)); } if (*p == '@') { char *str = (char*) args[*(p + 1) - '1']; if (str) { char *q = str + strlen(str) - 1; while (q >= str && !isalpha_pl_PL(*q)) q--; if (*q == 'a') string_append(buf, "a"); else string_append(buf, "y"); } p += 2; continue; } fill_before = 0; fill_after = 0; fill_length = 0; fill_char = ' '; fill_soft = 1; if (*p == '[' || *p == '(') { char *q; fill_soft = (*p == '('); p++; fill_char = ' '; if (*p == '.') { fill_char = '0'; p++; } else if (*p == ',') { fill_char = '.'; p++; } else if (*p == '_') { fill_char = '_'; p++; } fill_length = strtol(p, &q, 0); p = q; if (fill_length > 0) fill_after = 1; else { fill_length = -fill_length; fill_before = 1; } p++; } if (*p >= '1' && *p <= '9') { char *str = (char *) args[*p - '1']; int i, len; if (!str) str = ""; len = strlen(str); if (fill_length) { if (len >= fill_length) { if (!fill_soft) len = fill_length; fill_length = 0; } else fill_length -= len; } if (fill_before) for (i = 0; i < fill_length; i++) string_append_c(buf, fill_char); string_append_n(buf, str, len); if (fill_after) for (i = 0; i < fill_length; i++) string_append_c(buf, fill_char); } } else string_append_c(buf, *p); p++; } if (!dont_resolve && no_prompt_cache) theme_cache_reset(); if (!config_display_pl_chars) iso_to_ascii((unsigned char *) buf->str); #ifdef WITH_UI_GTK if (ui_init == ui_gtk_init) { buf->str = iso_to_utf8(buf->str); } #endif return string_free(buf, 0); } /* * reformat_string() * * zamienia sformatowany ciąg znaków ansi na Nowy-i-Lepszy(tm). * * - str - ciąg znaków, * * zwraca zaalokowaną fstring_t. */ fstring_t reformat_string(const char *str) { fstring_t res = xnew(struct fstring_s); unsigned char attr = 128; int i, j, len = 0; for (i = 0; str[i]; i++) { if (str[i] == 27) { if (str[i + 1] != '[') continue; while (str[i] && !isalpha_pl_PL(str[i])) i++; i--; continue; } if (str[i] == 9) { len += (8 - (len % 8)); continue; } if (str[i] == 13) continue; len++; } res->str = xmalloc(len + 1); res->attr = xmalloc(len + 1); res->prompt_len = 0; res->prompt_empty = 0; for (i = 0, j = 0; str[i]; i++) { if (str[i] == 27) { int tmp = 0; if (str[i + 1] != '[') continue; i += 2; /* obsługuje tylko "\033[...m", tak ma być */ for (; str[i]; i++) { if (str[i] >= '0' && str[i] <= '9') { tmp *= 10; tmp += (str[i] - '0'); } if (str[i] == ';' || isalpha_pl_PL(str[i])) { if (tmp == 0) { attr = 128; /* prompt jako \033[00m */ if (str[i - 1] == '0' && str[i - 2] == '0') res->prompt_len = j; /* odstęp jako \033[000m */ if (i > 3 && str[i - 1] == '0' && str[i - 2] == '0' && str[i - 3] == 0) { res->prompt_len = j; res->prompt_empty = 1; } } if (tmp == 1) attr |= 64; if (tmp >= 30 && tmp <= 37) { attr &= 120; attr |= (tmp - 30); } if (tmp >= 40 && tmp <= 47) { attr &= 71; attr |= (tmp - 40) << 3; } tmp = 0; } if (isalpha_pl_PL(str[i])) break; } continue; } if (str[i] == 13) continue; if (str[i] == 9) { int k = 0, l = 8 - (j % 8); for (k = 0; k < l; j++, k++) { res->str[j] = ' '; res->attr[j] = attr; } continue; } res->str[j] = str[i]; res->attr[j] = attr; j++; } res->str[j] = 0; res->attr[j] = 0; return res; } /* * format_string() * * j.w. tyle że nie potrzeba dawać mu va_list, a wystarczą zwykłe parametry. * * - format... - j.w., */ char *format_string(const char *format, ...) { va_list ap; char *tmp; va_start(ap, format); tmp = va_format_string(format, ap); va_end(ap); return tmp; } /* * print() * * drukuje na stdout tekst, biorąc pod uwagę nazwę, nie wartość formatu. * parametry takie jak zdefiniowano. pierwszy to %1, drugi to %2. */ void print(const char *theme, ...) { va_list ap; char *tmp; va_start(ap, theme); tmp = va_format_string(format_find(theme), ap); ui_print("__current", 0, (tmp) ? tmp : ""); xfree(tmp); va_end(ap); } /* * print_status() * * wyświetla tekst w oknie statusu. */ void print_status(const char *theme, ...) { va_list ap; char *tmp; va_start(ap, theme); tmp = va_format_string(format_find(theme), ap); ui_print("__status", 0, (tmp) ? tmp : ""); xfree(tmp); va_end(ap); } /* * print_window() * * wyświetla tekst w podanym oknie. * * - target - nazwa okna, * - separate - czy niezbędne jest otwieranie nowego okna? * - theme, ... - treść. */ void print_window(const char *target, int separate, const char *theme, ...) { va_list ap; char *tmp; if (!target) target = "__current"; va_start(ap, theme); tmp = va_format_string(format_find(theme), ap); ui_print(target, separate, (tmp) ? tmp : ""); xfree(tmp); va_end(ap); } /* * theme_cache_reset() * * usuwa cache'owane prompty. przydaje się przy zmianie theme'u. */ void theme_cache_reset() { xfree(prompt_cache); xfree(prompt2_cache); xfree(error_cache); prompt_cache = prompt2_cache = error_cache = NULL; timestamp_cache = NULL; } /* * format_add() * * dodaje daną formatkę do listy. * * - name - nazwa, * - value - wartość, * - replace - jeśli znajdzie, to zostawia (=0) lub zamienia (=1). */ int format_add(const char *name, const char *value, int replace) { struct format f; list_t l; int hash; if (!name || !value) return -1; hash = ekg_hash(name); if (hash == ekg_hash("no_prompt_cache") && !strcasecmp(name, "no_prompt_cache")) { no_prompt_cache = 1; return 0; } for (l = formats; l; l = l->next) { struct format *g = l->data; if (hash == g->name_hash && !strcasecmp(name, g->name)) { if (replace) { xfree(g->value); g->value = xstrdup(value); } return 0; } } f.name = xstrdup(name); f.name_hash = ekg_hash(name); f.value = xstrdup(value); return (list_add(&formats, &f, sizeof(f)) ? 0 : -1); } /* * format_remove() * * usuwa formatkę o danej nazwie. * * - name. */ int format_remove(const char *name) { list_t l; if (!name) return -1; for (l = formats; l; l = l->next) { struct format *f = l->data; if (!strcasecmp(f->name, name)) { xfree(f->value); xfree(f->name); list_remove(&formats, f, 1); return 0; } } return -1; } /* * try_open() // funkcja wewnętrzna * * próbuje otworzyć plik, jeśli jeszcze nie jest otwarty. * * - prevfd - deskryptor z poprzedniego wywołania, * - prefix - ścieżka, * - filename - nazwa pliku. */ static FILE *try_open(FILE *prevfd, const char *prefix, const char *filename) { char buf[PATH_MAX + 1]; int save_errno; FILE *f; if (prevfd) return prevfd; if (prefix) snprintf(buf, sizeof(buf), "%s/%s", prefix, filename); else snprintf(buf, sizeof(buf), "%s", filename); if ((f = fopen(buf, "r"))) return f; if (prefix) snprintf(buf, sizeof(buf), "%s/%s.theme", prefix, filename); else snprintf(buf, sizeof(buf), "%s.theme", filename); save_errno = errno; if ((f = fopen(buf, "r"))) return f; if (errno == ENOENT) errno = save_errno; return NULL; } /* * theme_read() * * wczytuje opis wyglądu z podanego pliku. * * - filename - nazwa pliku z opisem, * - replace - czy zastępować istniejące wpisy. * * zwraca 0 jeśli wszystko w porządku, -1 w przypadku błędu. */ int theme_read(const char *filename, int replace) { char *buf; FILE *f = NULL; if (!filename) { filename = prepare_path("default.theme", 0); if (!filename || !(f = fopen(filename, "r"))) return -1; } else { char *fn = xstrdup(filename), *tmp; if ((tmp = strchr(fn, ','))) *tmp = 0; errno = ENOENT; f = try_open(NULL, NULL, fn); if (!strchr(filename, '/')) { f = try_open(f, prepare_path("", 0), fn); f = try_open(f, prepare_path("themes", 0), fn); f = try_open(f, DATADIR "/themes", fn); } xfree(fn); if (!f) return -1; } theme_free(); theme_init(); ui_event("theme_init"); while ((buf = read_file(f))) { char *value, *p; if (buf[0] == '#') { xfree(buf); continue; } if (!(value = strchr(buf, ' '))) { xfree(buf); continue; } *value++ = 0; for (p = value; *p; p++) { if (*p == '\\') { if (!*(p + 1)) break; if (*(p + 1) == 'n') *p = '\n'; memmove(p + 1, p + 2, strlen(p + 1)); } } if (buf[0] == '-') format_remove(buf + 1); else format_add(buf, value, replace); xfree(buf); } fclose(f); theme_cache_reset(); return 0; } /* * theme_free() * * usuwa formatki z pamięci. */ void theme_free() { list_t l; for (l = formats; l; l = l->next) { struct format *f = l->data; xfree(f->name); xfree(f->value); } list_destroy(formats, 1); formats = NULL; theme_cache_reset(); } /* * theme_init() * * ustawia domyślne wartości formatek. */ void theme_init() { theme_cache_reset(); /* wykorzystywane w innych formatach */ format_add("prompt", "%K:%g:%G:%n", 1); format_add("prompt,speech", " ", 1); format_add("prompt2", "%K:%c:%C:%n", 1); format_add("prompt2,speech", " ", 1); format_add("error", "%K:%r:%R:%n", 1); format_add("error,speech", "błąd!", 1); format_add("timestamp", "%H:%M", 1); format_add("timestamp,speech", " ", 1); /* prompty dla ui-readline */ format_add("readline_prompt", "% ", 1); format_add("readline_prompt_away", "/ ", 1); format_add("readline_prompt_invisible", ". ", 1); format_add("readline_prompt_query", "%1> ", 1); format_add("readline_prompt_win", "%1%% ", 1); format_add("readline_prompt_away_win", "%1/ ", 1); format_add("readline_prompt_invisible_win", "%1. ", 1); format_add("readline_prompt_query_win", "%2:%1> ", 1); format_add("readline_prompt_win_act", "%1 (act/%2)%% ", 1); format_add("readline_prompt_away_win_act", "%1 (act/%2)/ ", 1); format_add("readline_prompt_invisible_win_act", "%1 (act/%2). ", 1); format_add("readline_prompt_query_win_act", "%2:%1 (act/%3)> ", 1); format_add("readline_more", "-- Wciśnij Enter by kontynuować lub Ctrl-D by przerwać --", 1); /* prompty i statusy dla ui-ncurses */ format_add("ncurses_prompt_none", "", 1); format_add("ncurses_prompt_query", "[%1] ", 1); format_add("statusbar", " %c(%w%{time}%c)%w %{?uin %c(%w%{?!nick uin}%{nick}%c/%{?away %w}%{?avail %W}%{?invisible %K}%{?notavail %k}%{uin}%c) }%c%{?window (%wwin%c/%w%{window}}%{?query %c:%W%{query}}%{?debug %c(%Cdebug}%c)%w%{?activity %c(%wact%c/%w}%{activity}%{?activity %c)%w}%{?mail %c(%wmail%c/%w}%{mail}%{?mail %c)}%{?more %c(%Gmore%c)}", 1); format_add("header", " %{?query %c(%{?query_away %w}%{?query_avail %W}%{?query_invisible %K}%{?query_notavail %k}%{query}%{?query_descr %c/%w%{query_descr}}%c) %{?query_ip (%wip%c/%w%{query_ip}%c)}}%{?!query %c(%wekg%c/%w%{version}%c) (%w%{url}%c)}", 1); format_add("ncurses_timestamp", "%H:%M", 1); /* dla funkcji format_user() */ format_add("known_user", "%T%1%n/%2", 1); format_add("known_user,speech", "%1", 1); format_add("unknown_user", "%T%1%n", 1); /* często wykorzystywane, różne, przydatne itd. */ format_add("none", "%1\n", 1); format_add("generic", "%> %1\n", 1); format_add("generic2", "%) %1\n", 1); format_add("generic_error", "%! %1\n", 1); format_add("debug", "%n%1\n", 1); format_add("fdebug", "%b%1\n", 1); format_add("iodebug", "%y%1\n", 1); format_add("iorecvdebug", "%Y%1\n", 1); format_add("edebug", "%R%1\n", 1); format_add("not_enough_params", "%! Za mało parametrów. Spróbuj %Thelp %1%n\n", 1); format_add("invalid_params", "%! Nieprawidłowe parametry. Spróbuj %Thelp %1%n\n", 1); format_add("invalid_uin", "%! Nieprawidłowy numer użytkownika\n", 1); format_add("invalid_nick", "%! Nieprawidłowa nazwa użytkownika\n", 1); format_add("user_not_found", "%! Nie znaleziono użytkownika %T%1%n\n", 1); format_add("not_implemented", "%! Tej funkcji jeszcze nie ma\n", 1); format_add("unknown_command", "%! Nieznane polecenie: %T%1%n\n", 1); format_add("welcome", "%> %TEKG-%1%n (Eksperymentalny Klient Gadu-Gadu)\n%> Program jest rozprowadzany na zasadach licencji GPL v2\n%> %RPrzed użyciem wciśnij F1 lub wpisz ,,help''%n\n\n", 1); format_add("welcome,speech", "witamy w e k g", 1); format_add("ekg_version", "%) EKG - Eksperymentalny Klient Gadu-Gadu (%T%1%n)\n%) libgadu-%1 (protokół %2, klient %3)\n%) skompilowano: %4\n", 1); format_add("secure", "%Y(szyfrowane)%n ", 1); format_add("log_failed", "%! Nie można zapisać do historii: %1\n", 1); format_add("var_not_set", "%! Wymagana zmienna %T%1%n nie została ustawiona\n", 1); /* mail */ format_add("new_mail_one", "%) Masz nową wiadomość email\n", 1); format_add("new_mail_two_four", "%) Masz %1 nowe wiadomości email\n", 1); format_add("new_mail_more", "%) Masz %1 nowych wiadomości email\n", 1); /* add, del */ format_add("user_added", "%> Dopisano %T%1%n do listy kontaktów\n", 1); format_add("user_deleted", "%) Usunięto %T%1%n z listy kontaktów\n", 1); format_add("user_cleared_list", "%) Wyczyszczono listę kontaktów\n", 1); format_add("user_exists", "%! %T%1%n już istnieje w liście kontaktów\n", 1); format_add("user_exists_other", "%! %T%1%n już istnieje w liście kontaktów jako %2\n", 1); /* zmiany stanu */ format_add("away", "%> Zmieniono stan na zajęty\n", 1); format_add("away_descr", "%> Zmieniono stan na zajęty: %T%1%n%2\n", 1); format_add("back", "%> Zmieniono stan na dostępny\n", 1); format_add("back_descr", "%> Zmieniono stan na dostępny: %T%1%n%2%n\n", 1); format_add("dnd", "%> Zmieniono stan na nie przeszkadzać\n", 1); format_add("dnd_descr", "%> Zmieniono stan na nie przeszkadzać: %T%1%n%2%n\n", 1); format_add("ffc", "%> Zmieniono stan na poGGadaj ze mną\n", 1); format_add("ffc_descr", "%> Zmieniono stan na poGGadaj ze mną: %T%1%n%2%n\n", 1); format_add("invisible", "%> Zmieniono stan na niewidoczny\n", 1); format_add("invisible_descr", "%> Zmieniono stan na niewidoczny: %T%1%n%2\n", 1); format_add("private_mode_is_on", "%> Tryb ,,tylko dla znajomych'' jest włączony\n", 1); format_add("private_mode_is_off", "%> Tryb ,,tylko dla znajomych'' jest wyłączony\n", 1); format_add("private_mode_on", "%> Włączono tryb ,,tylko dla znajomych''\n", 1); format_add("private_mode_off", "%> Wyłączono tryb ,,tylko dla znajomych''\n", 1); format_add("private_mode_invalid", "%! Nieprawidłowa wartość\n", 1); format_add("descr_too_long", "%! Długość opisu przekracza limit. Ilość uciętych znaków: %T%1%n\n", 1); /* pomoc */ format_add("help", "%> %T%1%n%2 - %3\n", 1); format_add("help_more", "%) %|%1\n", 1); format_add("help_alias", "%) %T%1%n jest aliasem i nie posiada opisu\n", 1); format_add("help_footer", "\n%> %|Więcej szczegółów na temat komend zwróci %Thelp %n. Opis zmiennych można otrzymać wpisując %Thelp set %n. Poprzedzenie komendy znakiem %T^%n spowoduje ukrycie jej wyniku. Zamiast parametru można użyć znaku %T$%n oznaczającego aktualnego rozmówcę.\n\n", 1); format_add("help_quick", "%> %|Przed użyciem przeczytaj ulotkę. Plik %Tdocs/ULOTKA%n zawiera krótki przewodnik po załączonej dokumentacji. Jeśli go nie masz, możesz ściągnąć pakiet ze strony %Thttp://ekg.chmurka.net/%n\n", 1); format_add("help_set_file_not_found", "%! Nie znaleziono opisu zmiennych (nieprawidłowa instalacja)\n", 1); format_add("help_set_var_not_found", "%! Nie znaleziono opisu zmiennej %T%1%n\n", 1); format_add("help_set_header", "%> %T%1%n (%2, domyślna wartość: %3)\n%>\n", 1); format_add("help_set_body", "%> %|%1\n", 1); format_add("help_set_footer", "", 1); /* ignore, unignore, block, unblock */ format_add("ignored_added", "%> Dodano %T%1%n do listy ignorowanych\n", 1); format_add("ignored_modified", "%> Zmodyfikowano poziom ignorowania %T%1%n\n", 1); format_add("ignored_deleted", "%) Usunięto %1 z listy ignorowanych\n", 1); format_add("ignored_deleted_all", "%) Usunięto wszystkich z listy ignorowanych\n", 1); format_add("ignored_exist", "%! %1 jest już na liście ignorowanych\n", 1); format_add("ignored_list", "%> %1 %2\n", 1); format_add("ignored_list_unknown_sender", "%> Ignorowanie wiadomości od nieznanych użytkowników\n", 1); format_add("ignored_list_empty", "%! Lista ignorowanych użytkowników jest pusta\n", 1); format_add("error_not_ignored", "%! %1 nie jest na liście ignorowanych\n", 1); format_add("blocked_added", "%> Dodano %T%1%n do listy blokowanych\n", 1); format_add("blocked_deleted", "%) Usunięto %1 z listy blokowanych\n", 1); format_add("blocked_deleted_all", "%) Usunięto wszystkich z listy blokowanych\n", 1); format_add("blocked_exist", "%! %1 jest już na liście blokowanych\n", 1); format_add("blocked_list", "%> %1\n", 1); format_add("blocked_list_empty", "%! Lista blokowanych użytkowników jest pusta\n", 1); format_add("error_not_blocked", "%! %1 nie jest na liście blokowanych\n", 1); /* lista kontaktów */ format_add("list_empty", "%! Lista kontaktów jest pusta\n", 1); format_add("list_avail", "%> %1 %Y(dostępn%@2)%n %b%3:%4%n\n", 1); format_add("list_avail_descr", "%> %1 %Y(dostępn%@2: %n%5%Y)%n %b%3:%4%n\n", 1); format_add("list_busy", "%> %1 %G(zajęt%@2)%n %b%3:%4%n\n", 1); format_add("list_busy_descr", "%> %1 %G(zajęt%@2: %n%5%G)%n %b%3:%4%n\n", 1); format_add("list_ffc", "%> %1 %y(poGGadaj ze mną)%n %b%3:%4%n\n", 1); format_add("list_ffc_descr", "%> %1 %y(poGGadaj ze mną: %n%5%y)%n %b%3:%4%n\n", 1); format_add("list_dnd", "%> %1 %g(nie przeszkadzać)%n %b%3:%4%n\n", 1); format_add("list_dnd_descr", "%> %1 %g(nie przeszkadzać: %n%5%g)%n %b%3:%4%n\n", 1); format_add("list_not_avail", "%> %1 %r(niedostępn%@2)%n\n", 1); format_add("list_not_avail_descr", "%> %1 %r(niedostępn%@2: %n%5%r)%n\n", 1); format_add("list_invisible", "%> %1 %c(niewidoczn%@2)%n %b%3:%4%n\n", 1); format_add("list_invisible_descr", "%> %1 %c(niewidoczn%@2: %n%5%c)%n %b%3:%4%n\n", 1); format_add("list_blocked", "%> %1 %m(blokując%@2)%n\n", 1); format_add("list_unknown", "%> %1\n", 1); format_add("modify_offline", "%> %1 nie będzie widzieć naszego stanu\n", 1); format_add("modify_online", "%> %1 będzie widzieć nasz stan\n", 1); format_add("modify_done", "%> Zmieniono wpis w liście kontaktów\n", 1); format_add("tab_cleared", "%> Wyczyszczono listę nicków do dopełnienia", 1); /* lista kontaktów z boku ekranu */ format_add("contacts_header", "", 1); format_add("contacts_header_group", "%K %1%n", 1); format_add("contacts_avail_header", "", 1); format_add("contacts_avail", " %Y%1%n", 1); format_add("contacts_avail_descr", "%Ki%Y%1%n", 1); format_add("contacts_avail_descr_full", "%Ki%Y%1%n %2", 1); format_add("contacts_avail_footer", "", 1); format_add("contacts_busy_header", "", 1); format_add("contacts_busy", " %G%1%n", 1); format_add("contacts_busy_descr", "%Ki%G%1%n", 1); format_add("contacts_busy_descr_full", "%Ki%G%1%n %2", 1); format_add("contacts_busy_footer", "", 1); format_add("contacts_ffc_header", "", 1); format_add("contacts_ffc", " %y%1%n", 1); format_add("contacts_ffc_descr", "%Ki%y%1%n", 1); format_add("contacts_ffc_descr_full", "%Ki%y%1%n %2", 1); format_add("contacts_ffc_footer", "", 1); format_add("contacts_dnd_header", "", 1); format_add("contacts_dnd", " %g%1%n", 1); format_add("contacts_dnd_descr", "%Ki%g%1%n", 1); format_add("contacts_dnd_descr_full", "%Ki%g%1%n %2", 1); format_add("contacts_dnd_footer", "", 1); format_add("contacts_not_avail_header", "", 1); format_add("contacts_not_avail", " %r%1%n", 1); format_add("contacts_not_avail_descr", "%Ki%r%1%n", 1); format_add("contacts_not_avail_descr_full", "%Ki%r%1%n %2", 1); format_add("contacts_not_avail_footer", "", 1); format_add("contacts_invisible_header", "", 1); format_add("contacts_invisible", " %c%1%n", 1); format_add("contacts_invisible_descr", "%Ki%c%1%n", 1); format_add("contacts_invisible_descr_full", "%Ki%c%1%n %2", 1); format_add("contacts_invisible_footer", "", 1); format_add("contacts_blocking_header", "", 1); format_add("contacts_blocking", " %m%1%n", 1); format_add("contacts_blocking_footer", "", 1); format_add("contacts_footer", "", 1); format_add("contacts_footer_group", "", 1); /* żegnamy się, zapisujemy konfigurację */ format_add("quit", "%> Papa\n", 1); format_add("quit_descr", "%> Papa: %T%1%n%2\n", 1); format_add("config_changed", "Zapisać nową konfigurację? (tak/nie) ", 1); format_add("saved", "%> Zapisano ustawienia\n", 1); format_add("error_saving", "%! Podczas zapisu ustawień wystąpił błąd\n", 1); /* przychodzące wiadomości */ format_add("message_header", "%g.-- %n%1 %c%2%n%4%g--- -- -%n\n", 1); format_add("message_conference_header", "%g.-- %g[%T%3%g] -- %n%1 %c%2%4%g--- -- -%n\n", 1); format_add("message_footer", "%g`----- ---- --- -- -%n\n", 1); format_add("message_line", "%g|%n %|%1%n\n", 1); format_add("message_line_width", "-8", 1); format_add("message_timestamp", "(%Y-%m-%d %H:%M) ", 1); format_add("message_timestamp_today", "(%H:%M) ", 1); format_add("message_timestamp_now", "", 1); format_add("message_header,speech", "wiadomość od %1: ", 1); format_add("message_conference_header,speech", "wiadomość od %1 w konferencji %3: ", 1); format_add("message_line,speech", "%1\n", 1); format_add("message_footer,speech", ".", 1); format_add("chat_header", "%c.-- %n%1 %c%2%n%4%c--- -- -%n\n", 1); format_add("chat_conference_header", "%c.-- %c[%T%3%c] -- %n%1 %c%2%4%c--- -- -%n\n", 1); format_add("chat_footer", "%c`----- ---- --- -- -%n\n", 1); format_add("chat_line", "%c|%n %|%1%n\n", 1); format_add("chat_line_width", "-8", 1); format_add("chat_timestamp", "(%Y-%m-%d %H:%M) ", 1); format_add("chat_timestamp_today", "(%H:%M) ", 1); format_add("chat_timestamp_now", "", 1); format_add("chat_header,speech", "wiadomość od %1: ", 1); format_add("chat_conference_header,speech", "wiadomość od %1 w konferencji %3: ", 1); format_add("chat_line,speech", "%1\n", 1); format_add("chat_footer,speech", ".", 1); format_add("sent_header", "%b.-- %n%1 %4%b--- -- -%n\n", 1); format_add("sent_conference_header", "%b.-- %b[%T%3%b] -- %4%n%1 %b--- -- -%n\n", 1); format_add("sent_footer", "%b`----- ---- --- -- -%n\n", 1); format_add("sent_line", "%b|%n %|%1%n\n", 1); format_add("sent_line_width", "-8", 1); format_add("sent_timestamp", "%H:%M", 1); format_add("sysmsg_header", "%m.-- %TWiadomość systemowa%m --- -- -%n\n", 1); format_add("sysmsg_line", "%m|%n %|%1%n\n", 1); format_add("sysmsg_line_width", "-8", 1); format_add("sysmsg_footer", "%m`----- ---- --- -- -%n\n", 1); format_add("sysmsg_header,speech", "wiadomość systemowa:", 1); format_add("sysmsg_line,speech", "%1\n", 1); format_add("sysmsg_footer,speech", ".", 1); /* potwierdzenia wiadomości */ format_add("ack_queued", "%> Wiadomość do %1 zostanie dostarczona później\n", 1); format_add("ack_delivered", "%> Wiadomość do %1 została dostarczona\n", 1); format_add("ack_filtered", "%! %|Wiadomość do %1 najprawdopodobniej nie została dostarczona, ponieważ dana osoba jest niedostępna, a serwer twierdzi, że doręczył wiadomość. Sytuacja taka ma miejsce, gdy wiadomość została odrzucona przez filtry serwera (np. zawiera adres strony WWW)\n", 1); format_add("ack_filtered_short", "%! %|Wiadomość do %1 najprawdopodobniej nie została dostarczona\n", 1); format_add("ack_mboxfull", "%! Wiadomość do %1 nie została dostarczona, użytkownik ma pełną skrzynkę\n", 1); format_add("ack_not_delivered", "%! Wiadomość do %1 nie została dostarczona\n", 1); format_add("message_too_long", "%! Wiadomość jest zbyt długa i została skrócona\n", 1); /* ludzie zmieniają stan */ format_add("status_avail", "%> %1 jest dostępn%@2\n", 1); format_add("status_avail_descr", "%> %1 jest dostępn%@2: %T%3%n\n", 1); format_add("status_busy", "%> %1 jest zajęt%@2\n", 1); format_add("status_busy_descr", "%> %1 jest zajęt%@2: %T%3%n\n", 1); format_add("status_dnd", "%> %1 jest nie przeszkadzać\n", 1); format_add("status_dnd_descr", "%> %1 jest nie przeszkadzać: %T%3%n\n", 1); format_add("status_ffc", "%> %1 chce poGGadać\n", 1); format_add("status_ffc_descr", "%> %1 chce poGGadać: %T%3%n\n", 1); format_add("status_not_avail", "%> %1 jest niedostępn%@2\n", 1); format_add("status_not_avail_descr", "%> %1 jest niedostępn%@2: %T%3%n\n", 1); format_add("status_invisible", "%> %1 jest niewidoczn%@2\n", 1); format_add("status_invisible_descr", "%> %1 jest niewidoczn%@2: %T%3%n\n", 1); format_add("user_is_connected", "%> %1 jest połączon%@2 z serwerem%n\n", 1); format_add("auto_away", "%> Automagicznie zmieniono stan na zajęty po %1 nieaktywności\n", 1); format_add("auto_away_descr", "%> Automagicznie zmieniono stan na zajęty po %1 nieaktywności: %T%2%n%3\n", 1); format_add("auto_back", "%> Automagicznie zmieniono stan na dostępny\n", 1); format_add("auto_back_descr", "%> Automagicznie zmieniono stan na dostępny: %T%2%n%3\n", 1); format_add("auto_dnd", "%> Automagicznie zmieniono stan na nie przeszkadzać\n", 1); format_add("auto_dnd_descr", "%> Automagicznie zmieniono stan na nie przeszkadzać: %T%2%n%3\n", 1); format_add("auto_ffc", "%> Automagicznie zmieniono stan na poGGadaj ze mną\n", 1); format_add("auto_ffc_descr", "%> Automagicznie zmieniono stan na poGGadaj ze mną: %T%2%n%3\n", 1); /* połączenie z serwerem */ format_add("connecting", "%> Łączę się z serwerem...\n", 1); format_add("conn_failed", "%! Połączenie nie udało się: %1\n", 1); format_add("conn_failed_resolving", "Nie znaleziono serwera", 1); format_add("conn_failed_connecting", "Nie można połączyć się z serwerem", 1); format_add("conn_failed_invalid", "Nieprawidłowa odpowiedź serwera", 1); format_add("conn_failed_disconnected", "Serwer zerwał połączenie", 1); format_add("conn_failed_password", "Nieprawidłowe hasło", 1); format_add("conn_failed_404", "Błąd serwera HTTP", 1); format_add("conn_failed_tls", "Błąd negocjacji TLS", 1); format_add("conn_failed_memory", "Brak pamięci", 1); format_add("conn_failed_intruder", "Zbyt wiele prób połączenia z nieprawidłowym hasłem", 1); format_add("conn_failed_unavailable", "Serwery GG są teraz wyłączone. Spróbuj później", 1); format_add("conn_stopped", "%! Przerwano łączenie\n", 1); format_add("conn_timeout", "%! Przekroczono limit czasu operacji łączenia z serwerem\n", 1); format_add("connected", "%> Połączono\n", 1); format_add("connected_descr", "%> Połączono: %T%1%n\n", 1); format_add("disconnected", "%> Rozłączono\n", 1); format_add("disconnected_descr", "%> Rozłączono: %T%1%n\n", 1); format_add("already_connected", "%! Klient jest już połączony. Wpisz %Treconnect%n aby połączyć ponownie\n", 1); format_add("during_connect", "%! Łączenie trwa. Wpisz %Tdisconnect%n aby przerwać\n", 1); format_add("conn_broken", "%! Połączenie zostało przerwane\n", 1); format_add("conn_disconnected", "%! Serwer zerwał połączenie\n", 1); format_add("not_connected", "%! Brak połączenia z serwerem. Wpisz %Tconnect%n\n", 1); format_add("not_connected_msg_queued", "%! Brak połączenia z serwerem. Wiadomość będzie wysłana po połączeniu.%n\n", 1); format_add("invalid_local_ip", "%! Nieprawidłowy adres lokalny.\n", 1); /* obsługa motywów */ format_add("theme_loaded", "%> Wczytano motyw %T%1%n\n", 1); format_add("theme_default", "%> Ustawiono domyślny motyw\n", 1); format_add("error_loading_theme", "%! Błąd podczas ładowania motywu: %1\n", 1); /* zmienne, konfiguracja */ format_add("variable", "%> %1 = %2\n", 1); format_add("variable_not_found", "%! Nieznana zmienna: %T%1%n\n", 1); format_add("variable_invalid", "%! Nieprawidłowa wartość zmiennej\n", 1); format_add("no_config", "%! Niekompletna konfiguracja. Wpisz:\n%! %Tset uin %n\n%! %Tset password %n\n%! %Tset email %n\n%! %Tsave%n\n%! Następnie wydaj polecenie:\n%! %Tconnect%n\n%! Jeśli nie masz swojego numerka, wpisz:\n%! %Ttoken%n\n%! %Tregister %n\n\n%> %|Po połączeniu, nowe okna rozmowy będą tworzone automatycznie, gdy ktoś przyśle wiadomość. Aby przejść do okna o podanym numerze należy wcisnąć %TAlt-numer%n lub %TEsc%n, a następnie cyfrę. Aby rozpocząć rozmowę, należy użyć polecenia %Tquery%n. Aby dodać kogoś do listy kontaktów, należy użyć polecenia %Tadd%n. Wszystkie kombinacje klawiszy są opisane w pliku %TREADME%n, a listę komend wyświetla polecenie %Thelp%n.\n\n", 2); format_add("no_config,speech", "niekompletna konfiguracja. wpisz set uin, a potem numer gadu-gadu, potem set pasłord, za tym swoje hasło, a następnie set imejl (bez myślnika), a za tym swój adres imejl. wpisz sejf, żeby zapisać ustawienia. wpisz konekt by się połączyć. niestety rejestracja wymaga odczytania z ekranu wysłanego przez serwer tokenu. po połączeniu, nowe okna rozmowy będą tworzone automatycznie, gdy ktoś przyśle wiadomość. aby przejść do okna o podanym numerze, należy wcisnąć alt-numer lub eskejp, a następnie cyfrę. aby rozpocząć rozmowę, należy użyć polecenia kłery. aby dodać kogoś do listy kontaktów, należy użyć polecenia edd. wszystkie kombinacje klawiszy są opisane w pliku ridmi, a listę komend wyświetla polecenie help.", 1); format_add("error_reading_config", "%! Nie można odczytać pliku konfiguracyjnego: %1\n", 1); format_add("config_read_success", "%> Wczytano plik konfiguracyjny %T%1%n\n", 1); format_add("config_line_incorrect", "%! Nieprawidłowa linia '%T%1%n', pomijam\n", 1); format_add("autosaved", "%> Automatycznie zapisano ustawienia\n", 1); /* rejestracja nowego numeru */ format_add("register", "%> Rejestracja poprawna. Wygrany numerek: %T%1%n\n", 1); format_add("register_failed", "%! Błąd podczas rejestracji: %1\n", 1); format_add("register_pending", "%! Rejestracja w toku\n", 1); format_add("register_timeout", "%! Przekroczono limit czasu operacji rejestrowania\n", 1); format_add("registered_today", "%! Już zarejestrowano jeden numer. Nie nadużywaj\n", 1); /* kasowanie konta użytkownika z katalogu publiczengo */ format_add("unregister", "%> Konto %T%1%n wykasowano\n", 1); format_add("unregister_timeout", "%! Przekroczono limit czasu operacji usuwania konta\n", 1); format_add("unregister_bad_uin", "%! Niepoprawny numer: %T%1%n\n", 1); format_add("unregister_failed", "%! Błąd podczas usuwania konta: %1\n", 1); /* przypomnienie hasła */ format_add("remind", "%> Hasło zostało wysłane\n", 1); format_add("remind_failed", "%! Błąd podczas wysyłania hasła: %1\n", 1); format_add("remind_timeout", "%! Przekroczono limit czasu operacji wysłania hasła\n", 1); /* zmiana hasła */ format_add("passwd", "%> Hasło zostało zmienione\n", 1); format_add("passwd_failed", "%! Błąd podczas zmiany hasła: %1\n", 1); format_add("passwd_timeout", "%! Przekroczono limit czasu operacji zmiany hasła\n", 1); format_add("passwd_email", "%! Należy ustawić zmienną %Temail%n\n", 1); /* zmiana informacji w katalogu publicznym */ format_add("change", "%> Informacje w katalogu publicznym zostały zmienione\n", 1); format_add("change_failed", "%! Błąd podczas zmiany informacji w katalogu publicznym\n", 1); /* pobieranie tokenu */ format_add("token", "%> Token zapisano do pliku %T%1%n\n", 1); format_add("token_ocr", "%> Token: %T%1%n\n", 1); format_add("token_body", "%1\n", 1); format_add("token_start", "%> Początek tokenu\n", 1); format_add("token_end", "%> Koniec tokenu\n", 1); format_add("token_failed", "%! Błąd pobierania tokenu: %1\n", 1); format_add("token_timeout", "%! Przekroczono limit czasu pobierania tokenu\n", 1); format_add("token_unsupported", "%! System operacyjny nie zawiera funkcji potrzebnych do obsługi tokenów\n", 1); format_add("token_missing", "%! Należy najpierw pobrać z serwera token komendą %Ttoken%n\n", 1); /* sesemesy */ format_add("sms_error", "%! Błąd wysyłania SMS: %1\n", 1); format_add("sms_unknown", "%! %1 nie ma podanego numeru komórki\n", 1); format_add("sms_sent", "%> SMS do %T%1%n został wysłany\n", 1); format_add("sms_failed", "%! SMS do %T%1%n nie został wysłany\n", 1); format_add("sms_msg", "EKG: msg %1 %# >> %2", 1); format_add("sms_chat", "EKG: chat %1 %# >> %2", 1); format_add("sms_conf", "EKG: conf %1 %# >> %2", 1); /* wyszukiwanie użytkowników */ format_add("search_failed", "%! Wystąpił błąd podczas szukania: %1\n", 1); format_add("search_not_found", "%! Nie znaleziono\n", 1); format_add("search_no_last", "%! Brak wyników ostatniego wyszukiwania\n", 1); format_add("search_no_last_nickname", "%! Brak pseudonimu w ostatnim wyszukiwaniu\n", 1); format_add("search_stopped", "%> Zatrzymano wyszukiwanie\n", 1); /* 1 uin, 2 name, 3 nick, 4 city, 5 born, 6 gender, 7 active */ format_add("search_results_multi_active", "%Y<>%n", 1); format_add("search_results_multi_busy", "%G<>%n", 1); format_add("search_results_multi_invisible", "%c<>%n", 1); format_add("search_results_multi_inactive", " ", 1); format_add("search_results_multi_unknown", "-", 1); /* format_add("search_results_multi_female", "k", 1); */ /* format_add("search_results_multi_male", "m", 1); */ format_add("search_results_multi", "%7 %[-8]1 %K|%n %[12]3 %K|%n %[12]2 %K|%n %[4]5 %K|%n %[12]4\n", 1); format_add("search_results_single_active", "%Y(dostępn%@1)%n", 1); format_add("search_results_single_busy", "%G(zajęt%@1)%n", 1); format_add("search_results_single_inactive", "%r(niedostępn%@1)%n", 1); format_add("search_results_single_invisible", "%c(niewidoczn%@1)%n", 1); format_add("search_results_single_unknown", "%T-%n", 1); /* format_add("search_results_single_female", "%Mkobieta%n", 1); */ /* format_add("search_results_single_male", "%Cmężczyzna%n", 1); */ format_add("search_results_single", "%) Pseudonim: %T%3%n\n%) Numerek: %T%1%n %7\n%) Imię i nazwisko: %T%2%n\n%) Miejscowość: %T%4%n\n%) Rok urodzenia: %T%5%n\n", 1); /* exec */ format_add("process", "%> %(-5)1 %2\n", 1); format_add("no_processes", "%! Nie ma działających procesów\n", 1); format_add("process_exit", "%> Proces %1 (%2) zakończył działanie z wynikiem %3\n", 1); format_add("exec", "%1\n",1); format_add("exec_error", "%! Błąd uruchamiania procesu: %1\n", 1); format_add("exec_prompt", "$ %1\n", 1); /* szczegółowe informacje o użytkowniku */ format_add("user_info_header", "%K.--%n %T%1%n/%2 %K--- -- -%n\n", 1); format_add("user_info_nickname", "%K| %nPseudonim: %T%1%n\n", 1); format_add("user_info_name", "%K| %nImię i nazwisko: %T%1 %2%n\n", 1); format_add("user_info_email", "%K| %nE-mail: %T%1%n\n", 1); format_add("user_info_status", "%K| %nStan: %T%1%n\n", 1); format_add("user_info_block", "%K| %nBlokowan%@1\n", 1); format_add("user_info_offline", "%K| %nNie widzi stanu\n", 1); format_add("user_info_not_in_contacts", "%K| %nNie ma nas w swoich kontaktach\n", 1); format_add("user_info_firewalled", "%K| %nZnajduje się za firewall/NAT\n", 1); format_add("user_info_ip", "%K| %nAdres: %T%1%n\n", 1); format_add("user_info_mobile", "%K| %nTelefon: %T%1%n\n", 1); format_add("user_info_groups", "%K| %nGrupy: %T%1%n\n", 1); format_add("user_info_never_seen", "%K| %nNie widziano podczas tej sesji\n", 1); format_add("user_info_last_seen", "%K| %nOstatnio widziano: %T%1%n\n", 1); format_add("user_info_last_seen_time", "%Y-%m-%d %H:%M", 1); format_add("user_info_last_descr", "%K| %nOstatni opis: %T%1%n\n", 1); format_add("user_info_version", "%K| %nWersja klienta: %T%1%n\n", 1); format_add("user_info_voip", "%K| %nObsługuje rozmowy głosowe\n", 1); format_add("user_info_last_ip","%K| %nOstatni adres IP: %T%1%n\n", 1); format_add("user_info_footer", "%K`----- ---- --- -- -%n\n", 1); format_add("user_info_avail", "%Ydostępn%@1%n", 1); format_add("user_info_avail_descr", "%Ydostępn%@1%n (%2)", 1); format_add("user_info_busy", "%Gzajęt%@1%n", 1); format_add("user_info_busy_descr", "%Gzajęt%@1%n (%2)", 1); format_add("user_info_ffc", "%ypoGGadaj ze mną%n", 1); format_add("user_info_ffc_descr", "%ypoGGadaj ze mną%n (%2)", 1); format_add("user_info_dnd", "%gnie przeszkadzać%n", 1); format_add("user_info_dnd_descr", "%gnie przeszkadzać%n (%2)", 1); format_add("user_info_not_avail", "%rniedostępn%@1%n", 1); format_add("user_info_not_avail_descr", "%rniedostępn%@1%n (%2)", 1); format_add("user_info_invisible", "%cniewidoczn%@1%n", 1); format_add("user_info_invisible_descr", "%cniewidoczn%@1%n (%2)", 1); format_add("user_info_blocked", "%mblokując%@1%n", 1); format_add("user_info_unknown", "%Mnieznany%n", 1); /* grupy */ format_add("group_members", "%> %|Grupa %T%1%n: %2\n", 1); format_add("group_member_already", "%! %1 należy już do grupy %T%2%n\n", 1); format_add("group_member_not_yet", "%! %1 nie należy do grupy %T%2%n\n", 1); format_add("group_empty", "%! Grupa %T%1%n jest pusta\n", 1); /* status */ format_add("show_status_profile", "%) Profil: %T%1%n\n", 1); format_add("show_status_uin", "%) Numer: %T%1%n\n", 1); format_add("show_status_uin_nick", "%) Numer: %T%1%n (%T%2%n)\n", 1); format_add("show_status_status", "%) Aktualny stan: %T%1%2%n\n", 1); format_add("show_status_server", "%) Aktualny serwer: %T%1%n:%T%2%n\n", 1); format_add("show_status_server_tls", "%) Aktualny serwer: %T%1%n:%T%2%n (połączenie szyfrowane)\n", 1); format_add("show_status_avail", "%Ydostępny%n", 1); format_add("show_status_avail_descr", "%Ydostępny%n (%T%1%n%2)", 1); format_add("show_status_busy", "%Gzajęty%n", 1); format_add("show_status_busy_descr", "%Gzajęty%n (%T%1%n%2)", 1); format_add("show_status_dnd", "%gnie przeszkadzać%n", 1); format_add("show_status_dnd_descr", "%gnie przeszkadzać%n (%T%1%n%2)", 1); format_add("show_status_ffc", "%ypoGGadaj ze mną%n", 1); format_add("show_status_ffc_descr", "%ypoGGadaj ze mną%n (%T%1%n%2)", 1); format_add("show_status_invisible", "%cniewidoczny%n", 1); format_add("show_status_invisible_descr", "%cniewidoczny%n (%T%1%n%2)", 1); format_add("show_status_not_avail", "%rniedostępny%n", 1); format_add("show_status_private_on", ", tylko dla znajomych", 1); format_add("show_status_private_off", "", 1); format_add("show_status_connected_since", "%) Połączony od: %T%1%n\n", 1); format_add("show_status_disconnected_since", "%) Rozłączony od: %T%1%n\n", 1); format_add("show_status_last_conn_event", "%Y-%m-%d %H:%M", 1); format_add("show_status_last_conn_event_today", "%H:%M", 1); format_add("show_status_ekg_started_since", "%) Program działa od: %T%1%n\n", 1); format_add("show_status_ekg_started", "%Y-%m-%d %H:%M", 1); format_add("show_status_ekg_started_today", "%H:%M", 1); format_add("show_status_msg_queue", "%) Ilość wiadomości w kolejce do wysłania: %T%1%n\n", 1); /* aliasy */ format_add("aliases_list_empty", "%! Brak aliasów\n", 1); format_add("aliases_list", "%> %T%1%n: %2\n", 1); format_add("aliases_list_next", "%> %3 %2\n", 1); format_add("aliases_add", "%> Utworzono alias %T%1%n\n", 1); format_add("aliases_append", "%> Dodano do aliasu %T%1%n\n", 1); format_add("aliases_del", "%) Usunięto alias %T%1%n\n", 1); format_add("aliases_del_all", "%) Usunięto wszystkie aliasy\n", 1); format_add("aliases_exist", "%! Alias %T%1%n już istnieje\n", 1); format_add("aliases_noexist", "%! Alias %T%1%n nie istnieje\n", 1); format_add("aliases_command", "%! %T%1%n jest wbudowaną komendą\n", 1); format_add("aliases_not_enough_params", "%! Alias %T%1%n wymaga większej ilości parametrów\n", 1); /* połączenia bezpośrednie */ format_add("dcc_attack", "%! %|Program otrzymał zbyt wiele żądań bezpośrednich połączeń, ostatnie od %1\n", 1); format_add("dcc_spoof", "%! %|Użytkownik %1 podał serwerowi adres %T%2%n, ale połączył się z nami z adresu %T%3%n. Możliwe, że ktoś próbuje się pod niego podszyć. Zachowaj ostrożność!\n", 1); format_add("dcc_limit", "%! %|Przekroczono limit bezpośrednich połączeń i dla bezpieczeństwa zostały one wyłączone. Aby je włączyć ponownie, należy wpisać polecenie %Tset dcc 1%n i połączyć się ponownie. Limit można zmienić za pomocą zmiennej %Tdcc_limit%n.\n", 1); format_add("dcc_create_error", "%! Nie można włączyć połączeń bezpośrednich: %1\n", 1); format_add("dcc_error", "%! Błąd transmisji: %1\n", 1); format_add("dcc_error_network", "%! Błąd transmisji z %1\n", 1); format_add("dcc_error_refused", "%! Połączenie z %1 zostało odrzucone\n", 1); format_add("dcc_error_unknown", "%! Nieznany błąd połączenia bezpośredniego\n", 1); format_add("dcc_error_handshake", "%! Nie można nawiązać połączenia z %1\n", 1); format_add("dcc_user_aint_dcc", "%! %1 nie ma włączonej obsługi połączeń bezpośrednich\n", 1); format_add("dcc_timeout", "%! Przekroczono limit czasu operacji bezpośredniego połączenia z %1\n", 1); format_add("dcc_not_supported", "%! Opcja %T%1%n nie jest jeszcze obsługiwana\n", 1); format_add("dcc_open_error", "%! Nie można otworzyć %T%1%n: %2\n", 1); format_add("dcc_show_pending_header", "%> Połączenia oczekujące:\n", 1); format_add("dcc_show_pending_send", "%) #%1, %2, wysyłanie %T%3%n\n", 1); format_add("dcc_show_pending_get", "%) #%1, %2, odbiór %T%3%n\n", 1); format_add("dcc_show_pending_voice", "%) #%1, %2, rozmowa\n", 1); format_add("dcc_show_active_header", "%> Połączenia aktywne:\n", 1); format_add("dcc_show_active_send", "%) #%1, %2, wysyłanie %T%3%n, %T%4b%n z %T%5b%n (%6%%)\n", 1); format_add("dcc_show_active_send_speed_s", "%) #%1, %2, wysyłanie %T%3%n, %T%4b%n z %T%5b%n (%6%%, %T%7%nkB/s, pozostało %T%8%ns)\n", 1); format_add("dcc_show_active_send_speed_ms", "%) #%1, %2, wysyłanie %T%3%n, %T%4b%n z %T%5b%n (%6%%, %T%7%nkB/s, pozostało %T%8%nm %T%9%ns)\n", 1); format_add("dcc_show_active_get", "%) #%1, %2, odbiór %T%3%n, %T%4b%n z %T%5b%n (%6%%)\n", 1); format_add("dcc_show_active_get_speed_s", "%) #%1, %2, odbiór %T%3%n, %T%4b%n z %T%5b%n (%6%%, %T%7%nkB/s, pozostało %T%8%ns)\n", 1); format_add("dcc_show_active_get_speed_ms", "%) #%1, %2, odbiór %T%3%n, %T%4b%n z %T%5b%n (%6%%, %T%7%nkB/s, pozostało %T%8%nm %T%9%ns)\n", 1); format_add("dcc_show_active_voice", "%) #%1, %2, rozmowa\n", 1); format_add("dcc_show_empty", "%! Brak bezpośrednich połączeń\n", 1); format_add("dcc_receiving_already", "%! Plik %T%1%n od użytkownika %2 jest już pobierany\n", 1); format_add("dcc_done_get", "%> Zakończono pobieranie pliku %T%2%n od %1\n", 1); format_add("dcc_done_send", "%> Zakończono wysyłanie pliku %T%2%n do %1\n", 1); format_add("dcc_close", "%) Zamknięto połączenie z %1\n", 1); format_add("dcc_voice_offer", "%) %1 chce rozmawiać\n%) Wpisz %Tdcc voice #%2%n, by rozpocząć rozmowę, lub %Tdcc close #%2%n, by anulować\n", 1); format_add("dcc_voice_running", "%! Można prowadzić tylko jedną rozmowę głosową na raz\n", 1); format_add("dcc_voice_unsupported", "%! Nie wkompilowano obsługi rozmów głosowych. Przeczytaj %Tdocs/voip.txt%n\n", 1); format_add("dcc_get_offer", "%) %1 przesyła plik %T%2%n o rozmiarze %T%3b%n\n%) Wpisz %Tdcc get #%4%n, by go odebrać, lub %Tdcc close #%4%n, by anulować\n", 1); format_add("dcc_get_offer_resume", "%) Plik istnieje już na dysku, więc można wznowić pobieranie poleceniem %Tdcc resume #%4%n\n", 1); format_add("dcc_get_getting", "%) Rozpoczęto pobieranie pliku %T%2%n od %1\n", 1); format_add("dcc_get_cant_create", "%! Nie można utworzyć pliku %T%1%n\n", 1); format_add("dcc_get_backup_made", "%) Plik %T%1%n istnieje. Pobierany plik zostanie zapisany jako %T%2%n\n", 1); format_add("dcc_get_cant_overwrite", "%! Plik %T%1%n i wszystkie jego kopie istnieją\n", 1); format_add("dcc_not_found", "%! Nie znaleziono połączenia %T%1%n\n", 1); format_add("dcc_invalid_ip", "%! Nieprawidłowy adres IP\n", 1); format_add("dcc_user_not_avail", "%! %1 musi być aktywn%@2, by móc nawiązać połączenie\n", 1); format_add("dcc_must_reconnect", "%) Aby zmiany odniosły skutek, należy ponownie połączyć się z serwerem\n", 1); /* query */ format_add("query_started", "%) Rozpoczęto rozmowę z %T%1%n\n", 1); format_add("query_started_window", "%) Wciśnij %TAlt-G%n by ignorować, %TAlt-K%n by zamknąć okno\n", 1); format_add("query_finished", "%) Zakończono rozmowę z %T%1%n\n", 1); format_add("query_exist", "%! Rozmowa z %T%1%n jest już prowadzona w okienku nr %T%2%n\n", 1); /* zdarzenia */ format_add("events_list_empty", "%! Brak zdarzeń\n", 1); format_add("events_list", "%> %4, on %1 %2 %3\n", 1); format_add("events_list_inactive", "%> %4, on %1 %2 %3 %K(nieaktywne)%n\n", 1); format_add("events_add", "%> Dodano zdarzenie %T%1%n\n", 1); format_add("events_del", "%) Usunięto zdarzenie %T%1%n\n", 1); format_add("events_del_all", "%) Usunięto wszystkie zdarzenia\n", 1); format_add("events_exist", "%! Zdarzenie %T%1%n istnieje dla %2\n", 1); format_add("events_del_noexist", "%! Zdarzenie %T%1%n nie istnieje\n", 1); format_add("events_seq_not_found", "%! Sekwencja %T%1%n nie znaleziona\n", 1); format_add("events_seq_incorrect", "%! Nieprawidłowa sekwencja\n", 1); /* lista kontaktów z serwera */ format_add("userlist_put_ok", "%> Listę kontaktów zachowano na serwerze\n", 1); format_add("userlist_put_error", "%! Błąd podczas wysyłania listy kontaktów\n", 1); format_add("userlist_get_ok", "%> Listę kontaktów wczytano z serwera\n", 1); format_add("userlist_get_error", "%! Błąd podczas pobierania listy kontaktów\n", 1); format_add("userlist_clear_ok", "%) Usunięto listę kontaktów z serwera\n", 1); format_add("userlist_clear_error", "%! Błąd podczas usuwania listy kontaktów\n", 1); format_add("userlist_config_put_ok", "%> Listę kontaktów i konfigurację zachowano na serwerze\n", 1); format_add("userlist_config_put_error", "%! Błąd podczas wysyłania listy kontaktów i konfiguracji\n", 1); format_add("userlist_config_get_ok", "%> Listę kontaktów i konfigurację wczytano z serwera\n", 1); format_add("userlist_config_get_error", "%! Błąd podczas pobierania listy kontaktów i konfiguracji\n", 1); format_add("userlist_config_clear_ok", "%) Usunięto listę kontaktów i konfigurację z serwera\n", 1); format_add("userlist_config_clear_error", "%! Błąd podczas usuwania listy kontaktów i konfiguracji\n", 1); format_add("userlist_backup_ok", "%> Zachowano kopię bezpieczeństwa listy kontaktów\n", 1); format_add("userlist_backup_failed", "%! Błąd podczas zachowywania kopii bezpieczeństwa listy kontaktów\n", 1); format_add("config_backup_ok", "%> Zachowano kopię bezpieczeństwa konfiguracji\n", 1); format_add("config_backup_failed", "%! Błąd podczas zachowywania kopii bezpieczeństwa konfiguracji\n", 1); /* szybka lista kontaktów pod F2 */ format_add("quick_list", "%)%1\n", 1); format_add("quick_list,speech", "lista kontaktów: ", 1); format_add("quick_list_avail", " %Y%1%n", 1); format_add("quick_list_avail,speech", "%1 jest dostępny, ", 1); format_add("quick_list_busy", " %G%1%n", 1); format_add("quick_list_busy,speech", "%1 jest zajęty, ", 1); format_add("quick_list_ffc", " %y%1%n", 1); format_add("quick_list_ffc,speech", "%1 jest poggadaj ze mną, ", 1); format_add("quick_list_dnd", " %g%1%n", 1); format_add("quick_list_dnd,speech", "%1 jest nie przeszkadzać, ", 1); format_add("quick_list_invisible", " %c%1%n", 1); /* window */ format_add("window_add", "%) Utworzono nowe okno\n", 1); format_add("window_noexist", "%! Wybrane okno nie istnieje\n", 1); format_add("window_no_windows", "%! Nie można zamknąć ostatniego okna\n", 1); format_add("window_del", "%) Zamknięto okno\n", 1); format_add("windows_max", "%! Wyczerpano limit ilości okien\n", 1); format_add("window_list_query", "%) %1: rozmowa z %T%2%n\n", 1); format_add("window_list_nothing", "%) %1: brak rozmowy\n", 1); format_add("window_list_floating", "%) %1: pływające %4x%5 w %2,%3 %T%6%n\n", 1); format_add("window_id_query_started", "%) Rozmowa z %T%2%n rozpoczęta w oknie %T%1%n\n", 1); format_add("window_kill_status", "%! Nie można zamknąć okna stanu\n", 1); format_add("window_dump_error", "%! Błąd zapisu do pliku %T%1%n\n", 1); format_add("window_dump_done", "%! Zapisano\n", 1); format_add("window_day_changed", "%) Zmiana daty: %T%1%n -> %T%2%n\n", 1); format_add("window_swapped", "%) Okna %T%1%n i %T%2%n zamienione miejscami\n", 1); /* bind */ format_add("bind_seq_incorrect", "%! Sekwencja %T%1%n jest nieprawidłowa\n", 1); format_add("bind_seq_add", "%> Dodano sekwencję %T%1%n\n", 1); format_add("bind_seq_remove", "%) Usunięto sekwencję %T%1%n\n", 1); format_add("bind_seq_list", "%> %1: %T%2%n\n", 1); format_add("bind_seq_exist", "%! Sekwencja %T%1%n ma już przypisaną akcję\n", 1); format_add("bind_seq_list_empty", "%! Brak przypisanych akcji\n", 1); /* at */ format_add("at_list", "%> %1, %2, %3 %K(%4)%n %5\n", 1); format_add("at_added", "%> Utworzono plan %T%1%n\n", 1); format_add("at_deleted", "%) Usunięto plan %T%1%n\n", 1); format_add("at_deleted_all", "%) Usunięto plany użytkownika\n", 1); format_add("at_exist", "%! Plan %T%1%n już istnieje\n", 1); format_add("at_noexist", "%! Plan %T%1%n nie istnieje\n", 1); format_add("at_empty", "%! Brak planów\n", 1); format_add("at_timestamp", "%d-%m-%Y %H:%M", 1); format_add("at_back_to_past", "%! Gdyby można było cofnąć czas...\n", 1); /* timer */ format_add("timer_list", "%> %1, %2s, %3 %K(%4)%n %T%5%n\n", 1); format_add("timer_added", "%> Utworzono timer %T%1%n\n", 1); format_add("timer_deleted", "%) Usunięto timer %T%1%n\n", 1); format_add("timer_deleted_all", "%) Usunięto timery użytkownika\n", 1); format_add("timer_exist", "%! Timer %T%1%n już istnieje\n", 1); format_add("timer_noexist", "%! Timer %T%1%n nie istnieje\n", 1); format_add("timer_empty", "%! Brak timerów\n", 1); /* last */ format_add("last_list_in", "%) %Y <<%n [%1] %2 %3\n", 1); format_add("last_list_out", "%) %G >>%n [%1] %2 %3\n", 1); format_add("last_list_empty", "%! Nie zalogowano wiadomości\n", 1); format_add("last_list_empty_nick", "%! Nie zalogowano wiadomości dla %T%1%n\n", 1); format_add("last_list_timestamp", "%d-%m-%Y %H:%M", 1); format_add("last_list_timestamp_today", "%H:%M", 1); format_add("last_clear", "%) Usunięto wiadomości\n", 1); format_add("last_clear_one", "%) Usunięto wiadomość\n", 1); /* queue */ format_add("queue_list_timestamp", "%d-%m-%Y %H:%M", 1); format_add("queue_list_message", "%) %G >>%n [%1] %2 %3\n", 1); format_add("queue_clear","%) Usunięto wiadomości z kolejki\n", 1); format_add("queue_clear_uin","%) Usunięto wiadomości z kolejki dla %T%1%n\n", 1); format_add("queue_wrong_use", "%! Komenda działa tylko w czasie braku połączenia z serwerem\n", 1); format_add("queue_empty", "%! Kolejka wiadomości jest pusta\n", 1); format_add("queue_empty_uin", "%! Brak wiadomości w kolejce dla %T%1%n\n", 1); format_add("queue_flush", "%> Wysłano zaległe wiadomości z kolejki\n", 1); /* conference */ format_add("conferences_list_empty", "%! Brak konferencji\n", 1); format_add("conferences_list", "%> %T%1%n: %2\n", 1); format_add("conferences_list_ignored", "%> %T%1%n: %2 (%yignorowana%n)\n", 1); format_add("conferences_add", "%> Utworzono konferencję %T%1%n\n", 1); format_add("conferences_not_added", "%! Nie utworzono konferencji %T%1%n\n", 1); format_add("conferences_del", "%) Usunięto konferencję %T%1%n\n", 1); format_add("conferences_del_all", "%) Usunięto wszystkie konferencje\n", 1); format_add("conferences_exist", "%! Konferencja %T%1%n już istnieje\n", 1); format_add("conferences_noexist", "%! Konferencja %T%1%n nie istnieje\n", 1); format_add("conferences_name_error", "%! Nazwa konferencji powinna zaczynać się od %T#%n\n", 1); format_add("conferences_rename", "%> Nazwa konferencji zmieniona: %T%1%n --> %T%2%n\n", 1); format_add("conferences_ignore", "%> Konferencja %T%1%n będzie ignorowana\n", 1); format_add("conferences_unignore", "%> Konferencja %T%1%n nie będzie ignorowana\n", 1); format_add("conferences_joined", "%> Dołączono %1 do konferencji %T%2%n\n", 1); format_add("conferences_already_joined", "%> %1 uczestniczy już w konferencji %T%2%n\n", 1); /* wspólne dla usług http */ format_add("http_failed_resolving", "Nie znaleziono serwera", 1); format_add("http_failed_connecting", "Nie można połączyć się z serwerem", 1); format_add("http_failed_reading", "Serwer zerwał połączenie", 1); format_add("http_failed_writing", "Serwer zerwał połączenie", 1); format_add("http_failed_memory", "Brak pamięci", 1); /* obrazki */ format_add("image_saved", "%> Zapisano obrazek od %T%1%n do pliku %T%2%n\n", 1); format_add("image_not_saved", "%! Błąd zapisywania obrazka od %T%1%n do pliku %T%2%n: %3!", 1); #ifdef HAVE_OPENSSL /* szyfrowanie */ format_add("key_generating", "%> Czekaj, generuję klucze...\n", 1); format_add("key_generating_success", "%> Wygenerowano i zapisano klucze\n", 1); format_add("key_generating_error", "%! Wystąpił błąd podczas generowania kluczy: %1\n", 1); format_add("key_private_exist", "%! Posiadasz już swoją parę kluczy\n", 1); format_add("key_public_deleted", "%) Klucz publiczny %1 został usunięty\n", 1); format_add("key_public_not_found", "%! Nie znaleziono klucza publicznego %1\n", 1); format_add("key_public_noexist", "%! Brak kluczy publicznych\n", 1); format_add("key_public_received", "%> Otrzymano klucz publiczny od %1\n", 1); format_add("key_public_write_failed", "%! Błąd podczas zapisu klucza publicznego: %1\n", 1); format_add("key_send_success", "%> Wysłano klucz publiczny do %1\n", 1); format_add("key_send_error", "%! Błąd podczas wysyłania klucza publicznego\n", 1); format_add("key_list", "%> %1 (%3)\n%) %2\n", 1); format_add("key_list_timestamp", "%Y-%m-%d %H:%M", 1); #endif #ifdef WITH_PYTHON /* python */ format_add("python_list", "%> %1\n", 1); format_add("python_list_empty", "%! Brak załadowanych skryptów\n", 1); format_add("python_removed", "%) Skrypt został usunięty\n", 1); format_add("python_need_name", "%! Nie podano nazwy skryptu\n", 1); format_add("python_not_found", "%! Nie znaleziono skryptu %T%1%n\n", 1); format_add("python_wrong_location", "%! Skrypt należy umieścić w katalogu %T%1%n\n", 1); #endif #ifdef WITH_ASPELL /* aspell */ format_add("aspell_init", "%> Czekaj, inicjuję moduł sprawdzania pisowni...\n", 1); format_add("aspell_init_success", "%> Zainicjowano moduł sprawdzania pisowni\n", 1); format_add("aspell_init_error", "%! Błąd modułu sprawdzania pisowni: %T%1%n\n", 1); #endif #ifdef HAVE_REGEX_H /* regex */ format_add("regex_error", "%! Błąd przetwarzania wyrażenia regularnego: %T%1%n\n", 1); format_add("regex_none", "%! Brak wyników spełniających kryteria wyszukiwania\n", 1); #endif } ekg-1.9~pre+r2855/src/themes.h000066400000000000000000000042631174410337000160510ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __THEMES_H #define __THEMES_H #include #include "dynstuff.h" struct format { char *name; int name_hash; char *value; }; struct fstring_s { char *str; /* znaki, ciąg zakończony \0 */ char *attr; /* atrybuty, ciąg o długości strlen(str) */ time_t ts; /* timestamp */ int prompt_len; /* długość promptu, który będzie powtarzany przy i przejściu do kolejnej linii. */ int prompt_empty; /* prompt przy przenoszeniu będzie pusty */ }; typedef struct fstring_s *fstring_t; list_t formats; void print(const char *theme, ...); void print_window(const char *target, int separate, const char *theme, ...); void print_status(const char *theme, ...); int format_add(const char *name, const char *value, int replace); int format_remove(const char *name); const char *format_find(const char *name); char *format_string(const char *format, ...); const char *format_ansi(char ch); void theme_init(void); int theme_read(const char *filename, int replace); void theme_cache_reset(void); void theme_free(void); fstring_t reformat_string(const char *str); /* * makro udające isalpha() z LC_CTYPE="pl_PL". niestety ncurses coś psuje * i źle wykrywa płeć. */ #define isalpha_pl_PL(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == 'ą' || x == 'ć' || x == 'ę' || x == 'ł' || x == 'ń' || x == 'ó' || x == 'ś' || x == 'ż' || x == 'ź' || x == 'Ą' || x == 'Ć' || x == 'Ę' || x == 'Ł' || x == 'Ń' || x == 'Ó' || x == 'Ś' || x == 'Ż' || x == 'Ź') #endif /* __THEMES_H */ ekg-1.9~pre+r2855/src/token.h000066400000000000000000000064101174410337000157000ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2003 Adam Czerwiński * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __TOKEN_H #define __TOKEN_H #ifdef HAVE_LIBJPEG const int token_char_height = 12; const char token_id_char[] = {"0123456789abcdef"}; const char token_id[][15] = { "..###..", ".#...#.", ".#...#.", "#.....#", "#.....#", "#.....#", "#.....#", "#.....#", "#.....#", ".#...#.", ".#...#.", "..###..", "..#", "###", "..#", "..#", "..#", "..#", "..#", "..#", "..#", "..#", "..#", "..#", "..###..", ".#...#.", "#.....#", "#.....#", "......#", ".....#.", "....#..", "...#...", "..#....", ".#.....", "#......", "#######", "..###..", ".#...#.", "#.....#", "#.....#", ".....#.", "..###..", ".....#.", "......#", "#.....#", "#.....#", ".#...#.", "..###..", ".....#.", "....##.", "....##.", "...#.#.", "..#..#.", "..#..#.", ".#...#.", "#....#.", "#######", ".....#.", ".....#.", ".....#.", "#######", "#......", "#......", "#......", "#.###..", "##...#.", "#.....#", "......#", "#.....#", "#.....#", ".#...#.", "..###..", "..###..", ".#...#.", "#.....#", "#......", "#.###..", "##...#.", "#.....#", "#.....#", "#.....#", "#.....#", ".#...#.", "..###..", "#######", "......#", "......#", ".....#.", ".....#.", "....#..", "....#..", "....#..", "...#...", "...#...", "...#...", "...#...", "..###..", ".#...#.", "#.....#", "#.....#", ".#...#.", "..###..", ".#...#.", "#.....#", "#.....#", "#.....#", ".#...#.", "..###..", "..###..", ".#...#.", "#.....#", "#.....#", "#.....#", "#.....#", ".#...##", "..###.#", "......#", "#.....#", ".#...#.", "..###..", "........", "........", "........", ".#####..", "#.....#.", "......#.", "......#.", ".######.", "#.....#.", "#.....#.", "#.....#.", ".#####.#", "#......", "#......", "#......", "#.###..", "##...#.", "#.....#", "#.....#", "#.....#", "#.....#", "#.....#", "##...#.", "#.###..", ".......", ".......", ".......", "..###..", ".#...#.", "#.....#", "#......", "#......", "#......", "#.....#", ".#...#.", "..###..", "......#", "......#", "......#", "..###.#", ".#...##", "#.....#", "#.....#", "#.....#", "#.....#", "#.....#", ".#...##", "..###.#", ".......", ".......", ".......", "..###..", ".#...#.", "#.....#", "#.....#", "#######", "#......", "#.....#", ".#...#.", "..###..", "...##", "..#..", "..#..", "#####", "..#..", "..#..", "..#..", "..#..", "..#..", "..#..", "..#..", "..#.."}; #endif #ifdef HAVE_LIBUNGIF /* Wyłączone, bo teraz nie używamy palety, ale jeśli ktoś wymyśli lepszy * algorytm wyświetlania obrazka (ten jest beznadziejnie prosty) to może * się przydać. */ #undef TOKEN_GIF_PAL struct token_t { size_t sx, sy; #ifdef TOKEN_GIF_PAL size_t pal_sz; unsigned char *pal; #endif unsigned char *data; }; #endif #endif /* __TOKEN_H */ ekg-1.9~pre+r2855/src/ui-batch.c000066400000000000000000000021561174410337000162520ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "stuff.h" #include "ui.h" static void loop() { while (batch_line) ekg_wait_for_key(); } static void nop() { } static int event(const char *foo, ...) { return 0; } static void print(const char *target, int separate, const char *line) { printf("%s", line); } void ui_batch_init() { ui_postinit = nop; ui_print = print; ui_loop = loop; ui_beep = nop; ui_event = event; ui_deinit = nop; } ekg-1.9~pre+r2855/src/ui-gtk-bindings.c000066400000000000000000000752211174410337000175540ustar00rootroot00000000000000/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * port to ekg2: * Copyright (C) 2007 Jakub Zawadzki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_STRLCPY # include "compat/strlcpy.h" #endif #include #include "commands.h" #include "userlist.h" #include "vars.h" #include "themes.h" #include "xmalloc.h" #include "ui-gtk.h" // #include "completion.h" #define COMPLETION_MAXLEN 2048 /* rozmiar linii */ #define GTK_BINDING_FUNCTION(x) int x(GtkWidget *wid, GdkEventKey *evt, char *d1, window_t *sess) /* These are cp'ed from history.c --AGL */ #define STATE_SHIFT GDK_SHIFT_MASK #define STATE_ALT GDK_MOD1_MASK #define STATE_CTRL GDK_CONTROL_MASK /*****************************************************************************************************/ static char **completions = NULL; /* lista dopełnień */ static void dcc_generator(const char *text, int len) { const char *words[] = { "close", "get", "send", "list", "resume", "rsend", "rvoice", "voice", NULL }; int i; for (i = 0; words[i]; i++) if (!strncasecmp(text, words[i], len)) array_add(&completions, xstrdup(words[i])); } static void command_generator(const char *text, int len) { const char *slash = "", *dash = ""; list_t l; if (*text == '/') { slash = "/"; text++; len--; } if (*text == '^') { dash = "^"; text++; len--; } if (window_current->target) slash = "/"; for (l = commands; l; l = l->next) { struct command *c = l->data; if (!strncasecmp(text, c->name, len)) array_add(&completions, saprintf("%s%s%s", slash, dash, c->name)); } } static void events_generator(const char *text, int len) { int i; const char *tmp = NULL; char *pre = NULL; if ((tmp = strrchr(text, '|')) || (tmp = strrchr(text, ','))) { char *foo; pre = xstrdup(text); foo = strrchr(pre, *tmp); *(foo + 1) = 0; len -= tmp - text + 1; tmp = tmp + 1; } else tmp = text; for (i = 0; event_labels[i].name; i++) if (!strncasecmp(tmp, event_labels[i].name, len)) array_add(&completions, ((tmp == text) ? xstrdup(event_labels[i].name) : saprintf("%s%s", pre, event_labels[i].name))); xfree(pre); } static void ignorelevels_generator(const char *text, int len) { int i; const char *tmp = NULL; char *pre = NULL; if ((tmp = strrchr(text, '|')) || (tmp = strrchr(text, ','))) { char *foo; pre = xstrdup(text); foo = strrchr(pre, *tmp); *(foo + 1) = 0; len -= tmp - text + 1; tmp = tmp + 1; } else tmp = text; for (i = 0; ignore_labels[i].name; i++) if (!strncasecmp(tmp, ignore_labels[i].name, len)) array_add(&completions, ((tmp == text) ? xstrdup(ignore_labels[i].name) : saprintf("%s%s", pre, ignore_labels[i].name))); xfree(pre); } static void unknown_uin_generator(const char *text, int len) { int i; for (i = 0; i < send_nicks_count; i++) { if (send_nicks[i] && xisdigit(send_nicks[i][0]) && !strncasecmp(text, send_nicks[i], len)) if (!array_contains(completions, send_nicks[i], 0)) array_add(&completions, xstrdup(send_nicks[i])); } } static void known_uin_generator(const char *text, int len) { list_t l; int done = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (u->display && u->uin && !strncasecmp(text, u->display, len)) { array_add_check(&completions, xstrdup(u->display), 1); done = 1; } } for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!done && u->uin && !strncasecmp(text, itoa(u->uin), len)) array_add_check(&completions, xstrdup(itoa(u->uin)), 1); } for (l = conferences; l; l = l->next) { struct conference *c = l->data; if (!strncasecmp(text, c->name, len)) array_add_check(&completions, xstrdup(c->name), 1); } unknown_uin_generator(text, len); } static void variable_generator(const char *text, int len) { list_t l; for (l = variables; l; l = l->next) { struct variable *v = l->data; if (v->type == VAR_FOREIGN || !v->ptr) continue; if (*text == '-') { if (!strncasecmp(text + 1, v->name, len - 1)) array_add(&completions, saprintf("-%s", v->name)); } else { if (!strncasecmp(text, v->name, len)) array_add(&completions, xstrdup(v->name)); } } } static void ignored_uin_generator(const char *text, int len) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!ignored_check(u->uin)) continue; if (!u->display) { if (!strncasecmp(text, itoa(u->uin), len)) array_add(&completions, xstrdup(itoa(u->uin))); } else { if (u->display && !strncasecmp(text, u->display, len)) array_add(&completions, xstrdup(u->display)); } } } static void blocked_uin_generator(const char *text, int len) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!group_member(u, "__blocked")) continue; if (!u->display) { if (!strncasecmp(text, itoa(u->uin), len)) array_add(&completions, xstrdup(itoa(u->uin))); } else { if (u->display && !strncasecmp(text, u->display, len)) array_add(&completions, xstrdup(u->display)); } } } static void empty_generator(const char *text, int len) { } static void file_generator(const char *text, int len) { struct dirent **namelist = NULL; char *dname, *tmp; const char *fname; int count, i; /* `dname' zawiera nazwę katalogu z kończącym znakiem `/', albo * NULL, jeśli w dopełnianym tekście nie ma ścieĹźki. */ dname = xstrdup(text); if ((tmp = strrchr(dname, '/'))) { tmp++; *tmp = 0; } else { xfree(dname); dname = NULL; } /* `fname' zawiera nazwę szukanego pliku */ fname = strrchr(text, '/'); if (fname) fname++; else fname = text; again: /* zbierzmy listę plikĂłw w żądanym katalogu */ count = scandir((dname) ? dname : ".", &namelist, NULL, alphasort); /* ui_debug("dname=\"%s\", fname=\"%s\", count=%d\n", (dname) ? dname : "(null)", (fname) ? fname : "(null)", count); */ for (i = 0; i < count; i++) { char *name = namelist[i]->d_name, *tmp = saprintf("%s%s", (dname) ? dname : "", name); struct stat st; int isdir = 0; if (!stat(tmp, &st)) isdir = S_ISDIR(st.st_mode); xfree(tmp); if (!strcmp(name, ".")) { xfree(namelist[i]); continue; } /* jeśli mamy `..', sprawdĹş czy katalog składa się z * `../../../' lub czegoś takiego. */ if (!strcmp(name, "..")) { const char *p; int omit = 0; for (p = dname; p && *p; p++) { if (*p != '.' && *p != '/') { omit = 1; break; } } if (omit) { xfree(namelist[i]); continue; } } if (!strncmp(name, fname, strlen(fname))) { name = saprintf("%s%s%s", (dname) ? dname : "", name, (isdir) ? "/" : ""); array_add(&completions, name); } xfree(namelist[i]); } /* jeśli w dopełnieniach wylądował tylko jeden wpis i jest katalogiem * to wejdĹş do niego i szukaj jeszcze raz */ if (array_count(completions) == 1 && strlen(completions[0]) > 0 && completions[0][strlen(completions[0]) - 1] == '/') { xfree(dname); dname = xstrdup(completions[0]); fname = ""; xfree(namelist); namelist = NULL; array_free(completions); completions = NULL; goto again; } xfree(dname); xfree(namelist); } static void python_generator(const char *text, int len) { const char *words[] = { "exec", "list", "load", "restart", "run", "unload", NULL }; int i; for (i = 0; words[i]; i++) if (!strncasecmp(text, words[i], len)) array_add(&completions, xstrdup(words[i])); } static void window_generator(const char *text, int len) { const char *words[] = { "new", "kill", "move", "next", "resize", "prev", "switch", "clear", "refresh", "list", "active", "last", "dump", NULL }; int i; for (i = 0; words[i]; i++) if (!strncasecmp(text, words[i], len)) array_add(&completions, xstrdup(words[i])); } static void reason_generator(const char *text, int len) { if (config_reason && !strncasecmp(text, config_reason, len)) { char *reason; /* brzydkie rozwiązanie, Ĺźeby nie ruszać opisu przy dopełnianiu */ if (xisspace(*config_reason)) reason = saprintf("\001\\%s", config_reason); else reason = saprintf("\001%s", config_reason); array_add(&completions, reason); } } static struct { char ch; void (*generate)(const char *text, int len); } generators[] = { { 'u', known_uin_generator }, { 'U', unknown_uin_generator }, { 'c', command_generator }, { 's', empty_generator }, { 'i', ignored_uin_generator }, { 'b', blocked_uin_generator }, { 'v', variable_generator }, { 'd', dcc_generator }, { 'p', python_generator }, { 'w', window_generator }, { 'f', file_generator }, { 'e', events_generator }, { 'I', ignorelevels_generator }, { 'r', reason_generator }, { 0, NULL } }; /* * complete() * * funkcja obsługująca dopełnianie klawiszem tab. * * Działanie: * - Wprowadzona linia dzielona jest na wyrazy (uwzględniając przecinki i znaki cudzyslowia) * - następnie znaki separacji znajdujące się między tymi wyrazami wrzucane są do tablicy separators * - dalej sprawdzane jest za pomocą zmiennej word_current (określającej aktualny wyraz bez uwzględnienia * przecinkĂłw - po to, aby wiedzieć czy w przypadku np funkcji /query ma być szukane dopełnienie * - zmienna word odpowiada za aktualny wyraz (*z* uwzględnieniem przecinkĂłw) * - words - tablica zawierają wszystkie wyrazy * - gdy jest to moĹźliwe szukane jest dopełnienie * - gdy dopełnień jest więcej niĹź jedno (count > 1) wyświetlamy tylko "wspĂłlną" część wszystkich dopełnień * np ,,que'' w przypadku funkcji /query i /queue * - gdy dopełnienie jest tylko jedno wyświetlamy owo dopełnienie * - przy wyświetlaniu dopełnienia cała linijka konstruowana jest od nowa, poniewaĹź nie wiadomo w ktĂłrym miejscu * podany wyraz ma zostań "wsadzony", stąd konieczna jest tablica separatorĂłw, tablica wszystkich wyrazĂłw itd ... */ static void complete(int *line_index, char *line) { char *start, *cmd, **words, *separators; int i, count, word, j, words_count, word_current, open_quote; /* * jeśli uzbierano juĹź coś to prĂłbujemy wyświetlić wszystkie moĹźliwości */ if (completions) { int maxlen = 0; int count = 0; char *tmp; for (i = 0; completions[i]; i++) { if (strlen(completions[i]) + 2 > maxlen) maxlen = strlen(completions[i]) + 2; count++; } tmp = xmalloc(count * maxlen + 2); tmp[0] = '\0'; for (i = 0; completions[i]; i++) { int k; strcat(tmp, completions[i]); for (k = 0; k < maxlen - strlen(completions[i]); k++) strcat(tmp, " "); } print("none", tmp); xfree(tmp); return; } start = xmalloc(strlen(line) + 1); /* zerujemy co mamy */ words = NULL; /* podziel (uwzględniając cudzysłowia)*/ for (i = 0, j = 0, open_quote = 0; i < strlen(line); i++) { if(line[i] == '"') { for(j = 0, i++; i < strlen(line) && line[i] != '"'; i++, j++) start[j] = line[i]; if (i == strlen(line)) open_quote = 1; } else for(j = 0; i < strlen(line) && !xisspace(line[i]) && line[i] != ','; j++, i++) start[j] = line[i]; start[j] = '\0'; /* "przewijamy" większą ilość spacji */ for(i++; i < strlen(line) && (xisspace(line[i]) || line[i] == ','); i++); i--; array_add(&words, saprintf("%s", start)); } /* jeĹźeli ostatnie znaki to spacja, albo przecinek to trzeba dodać jeszcze pusty wyraz do words */ if (strlen(line) > 1 && (line[strlen(line) - 1] == ' ' || line[strlen(line) - 1] == ',') && !open_quote) array_add(&words, xstrdup("")); /* for(i = 0; i < array_count(words); i++) gg_debug(GG_DEBUG_MISC, "words[i = %d] = \"%s\"\n", i, words[i]); */ /* inicjujemy pamięc dla separators */ if (words != NULL) separators = xmalloc(array_count(words) + 1); else separators = NULL; /* sprawdĹş, gdzie jesteśmy (uwzgędniając cudzysłowia) i dodaj separatory*/ for (word = 0, i = 0; i < strlen(line); i++, word++) { if(line[i] == '"') { for(j = 0, i++; i < strlen(line) && line[i] != '"'; j++, i++) start[j] = line[i]; } else { for(j = 0; i < strlen(line) && !xisspace(line[i]) && line[i] != ','; j++, i++) start[j] = line[i]; } /* "przewijamy */ for(i++; i < strlen(line) && (xisspace(line[i]) || line[i] == ','); i++); /* ustawiamy znak końca */ start[j] = '\0'; /* jeĹźeli to koniec linii, to kończymy tą zabawę */ if(i >= strlen(line)) break; /* obniĹźamy licznik o 1, Ĺźeby wszystko było okey, po "przewijaniu" */ i--; /* hmm, jesteśmy juĹź na wyrazie wskazywany przez kursor ? */ if(i >= *line_index) break; } /* dodajmy separatory - pewne rzeczy podobne do pętli powyĹźej */ for (i = 0, j = 0; i < strlen(line); i++, j++) { if(line[i] == '"') { for(i++; i < strlen(line) && line[i] != '"'; i++); if(i < strlen(line)) separators[j] = line[i + 1]; } else { for(; i < strlen(line) && !xisspace(line[i]) && line[i] != ','; i++); separators[j] = line[i]; } for(i++; i < strlen(line) && (xisspace(line[i]) || line[i] == ','); i++); i--; } if (separators) separators[j] = '\0'; // koniec ciagu /* aktualny wyraz bez uwzgledniania przecinkow */ for (i = 0, words_count = 0, word_current = 0; i < strlen(line); i++, words_count++) { for(; i < strlen(line) && !xisspace(line[i]); i++) if(line[i] == '"') for(i++; i < strlen(line) && line[i] != '"'; i++); for(i++; i < strlen(line) && xisspace(line[i]); i++); if(i >= strlen(line)) word_current = words_count + 1; i--; /* hmm, jesteśmy juĹź na wyrazie wskazywany przez kursor ? */ if(i >= *line_index) break; } /* trzeba pododawać trochę do licznikĂłw w spefycicznych (patrz warunki) sytuacjach */ if (strlen(line) > 1) { if((xisspace(line[strlen(line) - 1]) || line[strlen(line) - 1] == ',') && word + 1== array_count(words) -1 ) word++; if(xisspace(line[strlen(line) - 1]) && words_count == word_current) word_current++; if(xisspace(line[strlen(line) - 1])) words_count++; } /* gg_debug(GG_DEBUG_MISC, "word = %d\n", word); gg_debug(GG_DEBUG_MISC, "start = \"%s\"\n", start); gg_debug(GG_DEBUG_MISC, "words_count = %d\n", words_count); gg_debug(GG_DEBUG_MISC, "word_current = %d\n", word_current); */ /* for(i = 0; i < strlen(separators); i++) gg_debug(GG_DEBUG_MISC, "separators[i = %d] = \"%c\"\n", i, separators[i]); */ cmd = saprintf("/%s ", (config_tab_command) ? config_tab_command : "chat"); /* nietypowe dopełnienie nickĂłw przy rozmowach */ if (!strcmp(line, "") || (!strncasecmp(line, cmd, strlen(cmd)) && word == 2 && send_nicks_count > 0) || (!strcasecmp(line, cmd) && send_nicks_count > 0)) { if (send_nicks_index >= send_nicks_count) send_nicks_index = 0; if (send_nicks_count) { char *nick = send_nicks[send_nicks_index++]; snprintf(line, COMPLETION_MAXLEN, (strchr(nick, ' ')) ? "%s\"%s\" " : "%s%s ", cmd, nick); } else snprintf(line, COMPLETION_MAXLEN, "%s", cmd); *line_index = strlen(line); array_free(completions); array_free(words); xfree(start); xfree(separators); xfree(cmd); return; } xfree(cmd); /* początek komendy? */ if (word == 0) command_generator(start, strlen(start)); else { char *params = NULL; int abbrs = 0, i; list_t l; for (l = commands; l; l = l->next) { struct command *c = l->data; int len = strlen(c->name); char *cmd = (line[0] == '/') ? line + 1 : line; if (!strncasecmp(cmd, c->name, len) && xisspace(cmd[len])) { params = c->params; abbrs = 1; break; } for (len = 0; cmd[len] && cmd[len] != ' '; len++); if (!strncasecmp(cmd, c->name, len)) { params = c->params; abbrs++; } else if (params && abbrs == 1) break; } if (params && abbrs == 1) { for (i = 0; generators[i].ch; i++) { if (generators[i].ch == params[word_current - 2]) { int j; generators[i].generate(words[word], strlen(words[word])); for (j = 0; completions && completions[j]; j++) { string_t s; if (!strchr(completions[j], '"') && !strchr(completions[j], '\\') && !strchr(completions[j], ' ')) continue; s = string_init("\""); string_append(s, completions[j]); string_append_c(s, '\"'); xfree(completions[j]); completions[j] = string_free(s, 0); } break; } } } } count = array_count(completions); /* * jeśli jest tylko jedna moĹźlwiość na dopełnienie to drukujemy co mamy, * ewentualnie bierzemy część wyrazĂłw w cudzysłowia ... * i uwaĹźamy oczywiście na \001 (patrz funkcje wyĹźej */ if (count == 1) { line[0] = '\0'; for(i = 0; i < array_count(words); i++) { if(i == word) { if(strchr(completions[0], '\001')) { if(completions[0][0] == '"') strncat(line, completions[0] + 2, strlen(completions[0]) - 2 - 1 ); else strncat(line, completions[0] + 1, strlen(completions[0]) - 1); } else strcat(line, completions[0]); *line_index = strlen(line) + 1; } else { if(strchr(words[i], ' ')) { char *buf = saprintf("\"%s\"", words[i]); strcat(line, buf); xfree(buf); } else strcat(line, words[i]); } if((i == array_count(words) - 1 && line[strlen(line) - 1] != ' ' )) strcat(line, " "); else if (line[strlen(line) - 1] != ' ') { size_t slen = strlen(line); line[slen] = separators[i]; line[slen + 1] = '\0'; } } array_free(completions); completions = NULL; } /* * gdy jest więcej moĹźliwości to robimy podobnie jak wyĹźej tyle, Ĺźe czasem * trzeba uĹźyć cudzysłowia tylko z jednej storny, no i trzeba dopełnić do pewnego miejsca * w sumie proste rzeczy, ale jak widać jest trochę opcji ... */ if (count > 1) { int common = 0; int tmp = 0; int quotes = 0; char *s1 = completions[0]; if (*s1 =='"') s1++; /* * moĹźe nie za ładne programowanie, ale skuteczne i w sumie jedyne w 100% spełniające * wymagania dopełniania (uwzględnianie cudzywsłowiĂłw itp...) */ for(i=1, j = 0; ; i++, common++) { for(j=0; j < count; j++) { char *s2; s2 = completions[j]; if (*s2 == '"') { s2++; quotes = 1; } tmp = strncasecmp(s1, s2, i); /* gg_debug(GG_DEBUG_MISC,"strncasecmp(\"%s\", \"%s\", %d) = %d\n", s1, s2, i, strncasecmp(s1, s2, i)); */ if (tmp) break; } if (tmp) break; } /* gg_debug(GG_DEBUG_MISC,"common :%d\n", common); */ if (strlen(line) + common < COMPLETION_MAXLEN) { line[0] = '\0'; for(i = 0; i < array_count(words); i++) { if(i == word) { if(quotes == 1 && completions[0][0] != '"') strcat(line, "\""); if(completions[0][0] == '"') common++; if(common > 0 && completions[0][common - 1] == '"') common--; strncat(line, completions[0], common); *line_index = strlen(line); } else { if(strrchr(words[i], ' ')) { char *buf; buf = saprintf("\"%s\"", words[i]); strcat(line, buf); xfree(buf); } else strcat(line, words[i]); } if (separators[i]) { size_t slen = strlen(line); line[slen] = separators[i]; line[slen + 1] = '\0'; } } } } array_free(words); xfree(start); xfree(separators); return; } static GTK_BINDING_FUNCTION(key_action_scroll_page) { int value, end; GtkAdjustment *adj; enum scroll_type { PAGE_UP, PAGE_DOWN, LINE_UP, LINE_DOWN }; int type = PAGE_DOWN; if (d1) { if (!strcasecmp(d1, "up")) type = PAGE_UP; else if (!strcasecmp(d1, "+1")) type = LINE_DOWN; else if (!strcasecmp(d1, "-1")) type = LINE_UP; } if (!sess) return 0; adj = GTK_RANGE(gtk_private_ui(sess)->vscrollbar)->adjustment; end = adj->upper - adj->lower - adj->page_size; switch (type) { case LINE_UP: value = adj->value - 1.0; break; case LINE_DOWN: value = adj->value + 1.0; break; case PAGE_UP: value = adj->value - (adj->page_size - 1); break; default: /* PAGE_DOWN */ value = adj->value + (adj->page_size - 1); break; } if (value < 0) value = 0; if (value > end) value = end; gtk_adjustment_set_value(adj, value); return 0; } static GTK_BINDING_FUNCTION(key_action_history_up) { if (history_index < HISTORY_MAX && history[history_index + 1]) { /* for each line? */ if (history_index == 0) { xfree(history[0]); history[0] = xstrdup((GTK_ENTRY(wid)->text)); } history_index++; gtk_entry_set_text(GTK_ENTRY(wid), history[history_index]); gtk_editable_set_position(GTK_EDITABLE(wid), -1); } return 2; } static GTK_BINDING_FUNCTION(key_action_history_down) { if (history_index > 0) { history_index--; gtk_entry_set_text(GTK_ENTRY(wid), history[history_index]); gtk_editable_set_position(GTK_EDITABLE(wid), -1); } return 2; } static GTK_BINDING_FUNCTION(key_action_tab_comp) { char buf[COMPLETION_MAXLEN]; const char *text; int cursor_pos; /* in fjuczer, use g_completion_new() ? */ text = ((GTK_ENTRY(wid)->text)); if (text[0] == '\0') return 1; cursor_pos = gtk_editable_get_position(GTK_EDITABLE(wid)); if (strlcpy(buf, text, sizeof(buf)) >= sizeof(buf)) printf("key_action_tab_comp(), strlcpy() UUUUUUUCH!\n"); complete(&cursor_pos, buf); gtk_entry_set_text(GTK_ENTRY(wid), buf); gtk_editable_set_position(GTK_EDITABLE(wid), cursor_pos); return 2; } gboolean key_handle_key_press(GtkWidget *wid, GdkEventKey * evt, window_t *sess) { int keyval = evt->keyval; int mod, n; int was_complete = 0; list_t l; { sess = NULL; /* where did this event come from? */ for (l = windows; l; l = l->next) { window_t *w = l->data; if (gtk_private_ui(w)->input_box == wid) { sess = w; if (gtk_private_ui(w)->is_tab) sess = window_current; break; } } } if (!sess) { printf("key_handle_key_press() FAILED (sess == NULL)\n"); return FALSE; } /* printf("key_handle_key_press() %p [%d %d %d %s]\n", sess, evt->state, evt->keyval, evt->length, evt->string); */ /* XXX, EMIT: KEY_PRESSED */ mod = evt->state & (STATE_CTRL | STATE_ALT | STATE_SHIFT); n = -1; /* yeah, i know it's awful. */ if (keyval == GDK_Page_Up) n = key_action_scroll_page(wid, evt, "up", sess); else if (keyval == GDK_Page_Down) n = key_action_scroll_page(wid, evt, "down", sess); else if (keyval == GDK_Up) n = key_action_history_up(wid, evt, NULL, sess); else if (keyval == GDK_Down) n = key_action_history_down(wid, evt, NULL, sess); else if (keyval == GDK_Tab) { n = key_action_tab_comp(wid, evt, NULL, sess); was_complete = 1; } #ifndef GG_DEBUG_DISABLE else if (keyval == GDK_F12) command_exec(sess->target, "/window switch 0", 0); #endif else if (keyval == GDK_F1) command_exec(sess->target, "/help", 0); else if (keyval == GDK_0 && mod == STATE_ALT) command_exec(sess->target, "/window switch 10", 0); else if (keyval == GDK_9 && mod == STATE_ALT) command_exec(sess->target, "/window switch 9", 0); else if (keyval == GDK_8 && mod == STATE_ALT) command_exec(sess->target, "/window switch 8", 0); else if (keyval == GDK_7 && mod == STATE_ALT) command_exec(sess->target, "/window switch 7", 0); else if (keyval == GDK_6 && mod == STATE_ALT) command_exec(sess->target, "/window switch 6", 0); else if (keyval == GDK_5 && mod == STATE_ALT) command_exec(sess->target, "/window switch 5", 0); else if (keyval == GDK_4 && mod == STATE_ALT) command_exec(sess->target, "/window switch 4", 0); else if (keyval == GDK_3 && mod == STATE_ALT) command_exec(sess->target, "/window switch 3", 0); else if (keyval == GDK_2 && mod == STATE_ALT) command_exec(sess->target, "/window switch 2", 0); else if (keyval == GDK_1 && mod == STATE_ALT) command_exec(sess->target, "/window switch 1", 0); #ifndef GG_DEBUG_DISABLE else if (keyval == '`' && mod == STATE_ALT) command_exec(sess->target, "/window switch 0", 0); #endif else if (((keyval == GDK_Q) || (keyval == GDK_q)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 11", 0); else if (((keyval == GDK_W) || (keyval == GDK_w)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 12", 0); else if (((keyval == GDK_E) || (keyval == GDK_e)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 13", 0); else if (((keyval == GDK_R) || (keyval == GDK_r)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 14", 0); else if (((keyval == GDK_T) || (keyval == GDK_t)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 15", 0); else if (((keyval == GDK_Y) || (keyval == GDK_y)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 16", 0); else if (((keyval == GDK_U) || (keyval == GDK_u)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 17", 0); else if (((keyval == GDK_I) || (keyval == GDK_i)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 18", 0); else if (((keyval == GDK_O) || (keyval == GDK_o)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 19", 0); else if (((keyval == GDK_P) || (keyval == GDK_p)) && mod == STATE_ALT) command_exec(sess->target, "/window switch 20", 0); else if (((keyval == GDK_N) || (keyval == GDK_n)) && mod == STATE_ALT) command_exec(sess->target, "/window new", 0); else if (((keyval == GDK_K) || (keyval == GDK_k)) && mod == STATE_ALT) command_exec(sess->target, "/window kill", 0); else if (((keyval == GDK_A) || (keyval == GDK_a)) && mod == STATE_ALT) command_exec(sess->target, "/window active", 0); else if (((keyval == GDK_N) || (keyval == GDK_n)) && mod == STATE_CTRL) command_exec(sess->target, "/window next", 0); else if (((keyval == GDK_P) || (keyval == GDK_p)) && mod == STATE_CTRL) command_exec(sess->target, "/window prev", 0); else if (((keyval == GDK_F) || (keyval == GDK_f)) && mod == STATE_CTRL) n = key_action_scroll_page(wid, evt, "up", sess); else if (((keyval == GDK_G) || (keyval == GDK_g)) && mod == STATE_CTRL) n = key_action_scroll_page(wid, evt, "down", sess); /* BINDINGI XCHATOWE */ /* Najwazniejszy jest: F9 + kolorki. */ #if 0 "C\no\nInsert in Buffer\nD1:\nD2!\n\n"\ "C\nb\nInsert in Buffer\nD1:\nD2!\n\n"\ "C\nk\nInsert in Buffer\nD1:\nD2!\n\n"\ "S\nNext\nChange Selected Nick\nD1!\nD2!\n\n"\ "S\nPrior\nChange Selected Nick\nD1:Up\nD2!\n\n"\ "None\nNext\nScroll Page\nD1:Down\nD2!\n\n"\ "None\nPrior\nScroll Page\nD1:Up\nD2!\n\n"\ "None\nspace\nCheck For Replace\nD1!\nD2!\n\n"\ "None\nReturn\nCheck For Replace\nD1!\nD2!\n\n"\ "None\nKP_Enter\nCheck For Replace\nD1!\nD2!\n\n"\ "A\nLeft\nMove front tab left\nD1!\nD2!\n\n"\ "A\nRight\nMove front tab right\nD1!\nD2!\n\n"\ "CS\nPrior\nMove tab family left\nD1!\nD2!\n\n"\ "CS\nNext\nMove tab family right\nD1!\nD2!\n\n"\ "None\nF9\nRun Command\nD1:/GUI MENU TOGGLE\nD2!\n\n" #endif #if 0 binding_add("Alt-S", "/window oldest", 1, 1); binding_add("Alt-G", "ignore-query", 1, 1); binding_add("Alt-B", "backward-word", 1, 1); binding_add("Alt-F", "forward-word", 1, 1); binding_add("Alt-D", "kill-word", 1, 1); binding_add("Alt-Enter", "toggle-input", 1, 1); binding_add("Escape", "cancel-input", 1, 1); binding_add("Backspace", "backward-delete-char", 1, 1); binding_add("Ctrl-H", "backward-delete-char", 1, 1); binding_add("Ctrl-A", "beginning-of-line", 1, 1); binding_add("Home", "beginning-of-line", 1, 1); binding_add("Ctrl-D", "delete-char", 1, 1); binding_add("Delete", "delete-char", 1, 1); binding_add("Ctrl-E", "end-of-line", 1, 1); binding_add("End", "end-of-line", 1, 1); binding_add("Ctrl-K", "kill-line", 1, 1); binding_add("Ctrl-Y", "yank", 1, 1); binding_add("Enter", "accept-line", 1, 1); binding_add("Ctrl-M", "accept-line", 1, 1); binding_add("Ctrl-U", "line-discard", 1, 1); binding_add("Ctrl-V", "quoted-insert", 1, 1); binding_add("Ctrl-W", "word-rubout", 1, 1); binding_add("Alt-Backspace", "word-rubout", 1, 1); binding_add("Ctrl-L", "/window refresh", 1, 1); binding_add("Right", "forward-char", 1, 1); binding_add("Left", "backward-char", 1, 1); binding_add("Up", "previous-history", 1, 1); binding_add("Down", "next-history", 1, 1); binding_add("Ctrl-F", "backward-page", 1, 1); binding_add("Ctrl-G", "forward-page", 1, 1); binding_add("F2", "quick-list", 1, 1); binding_add("F3", "toggle-contacts", 1, 1); binding_add("F4", "next-contacts-group", 1, 1); binding_add("F11", "ui-ncurses-debug-toggle", 1, 1); binding_add("Alt-Z", "contacts-scroll-up", 1, 1); binding_add("Alt-X", "contacts-scroll-down", 1, 1); #endif #if 0 for (l = bindings; l; l = l->next) { if (kb->keyval == keyval && kb->mod == mod) { /* Run the function */ n = key_actions[kb->action].handler(wid, evt, kb->data1, kb->data2, sess); switch (n) { case 0: return 1; case 2: g_signal_stop_emission_by_name(G_OBJECT(wid), "key_press_event"); return 1; } } } #endif if (!was_complete) { /* jeśli się coś zmieniło, wygeneruj dopełnienia na nowo */ array_free(completions); completions = NULL; /* w xchacie bylo tylko na GDK_space */ } if (n == 2) { g_signal_stop_emission_by_name(G_OBJECT(wid), "key_press_event"); return 1; } return (n == 0); } void gtk_binding_init() { } static void gtk_binding_destroy() { } ekg-1.9~pre+r2855/src/ui-gtk-chanview-tabs.c000066400000000000000000000366211174410337000205130ustar00rootroot00000000000000/* file included in chanview.c */ typedef struct { GtkWidget *outer; /* outer box */ GtkWidget *inner; /* inner box */ GtkWidget *b1; /* button1 */ GtkWidget *b2; /* button2 */ } tabview; static void chanview_populate(chanview * cv); /* ignore "toggled" signal? */ static int ignore_toggle = FALSE; static int tab_left_is_moving = 0; static int tab_right_is_moving = 0; /* userdata for gobjects used here: * * tab (togglebuttons inside boxes): * "u" userdata passed to tab-focus callback function (sess) * "c" the tab's (chan *) */ /* * GtkViewports request at least as much space as their children do. * If we don't intervene here, the GtkViewport will be granted its * request, even at the expense of resizing the top-level window. */ static void cv_tabs_sizerequest(GtkWidget *viewport, GtkRequisition * requisition, chanview * cv) { if (!cv->vertical) requisition->width = 1; else requisition->height = 1; } static void cv_tabs_sizealloc(GtkWidget *widget, GtkAllocation * allocation, chanview * cv) { GtkAdjustment *adj; GtkWidget *inner; gint viewport_size; inner = ((tabview *) cv)->inner; if (cv->vertical) { adj = gtk_viewport_get_vadjustment(GTK_VIEWPORT(inner->parent)); gdk_window_get_geometry(inner->parent->window, 0, 0, 0, &viewport_size, 0); } else { adj = gtk_viewport_get_hadjustment(GTK_VIEWPORT(inner->parent)); gdk_window_get_geometry(inner->parent->window, 0, 0, &viewport_size, 0, 0); } if (adj->upper <= viewport_size) { gtk_widget_hide(((tabview *) cv)->b1); gtk_widget_hide(((tabview *) cv)->b2); } else { gtk_widget_show(((tabview *) cv)->b1); gtk_widget_show(((tabview *) cv)->b2); } } static gint tab_search_offset(GtkWidget *inner, gint start_offset, gboolean forward, gboolean vertical) { GList *boxes; GList *tabs; GtkWidget *box; GtkWidget *button; gint found; boxes = GTK_BOX(inner)->children; if (!forward && boxes) boxes = g_list_last(boxes); while (boxes) { box = ((GtkBoxChild *) boxes->data)->widget; boxes = (forward ? boxes->next : boxes->prev); tabs = GTK_BOX(box)->children; if (!forward && tabs) tabs = g_list_last(tabs); while (tabs) { button = ((GtkBoxChild *) tabs->data)->widget; tabs = (forward ? tabs->next : tabs->prev); if (!GTK_IS_TOGGLE_BUTTON(button)) continue; found = (vertical ? button->allocation.y : button->allocation.x); if ((forward && found > start_offset) || (!forward && found < start_offset)) return found; } } return 0; } static void tab_scroll_left_up_clicked(GtkWidget *widget, chanview * cv) { GtkAdjustment *adj; gint viewport_size; gfloat new_value; GtkWidget *inner; gfloat i; inner = ((tabview *) cv)->inner; if (cv->vertical) { adj = gtk_viewport_get_vadjustment(GTK_VIEWPORT(inner->parent)); gdk_window_get_geometry(inner->parent->window, 0, 0, 0, &viewport_size, 0); } else { adj = gtk_viewport_get_hadjustment(GTK_VIEWPORT(inner->parent)); gdk_window_get_geometry(inner->parent->window, 0, 0, &viewport_size, 0, 0); } new_value = tab_search_offset(inner, adj->value, 0, cv->vertical); if (new_value + viewport_size > adj->upper) new_value = adj->upper - viewport_size; if (!tab_left_is_moving) { tab_left_is_moving = 1; for (i = adj->value; ((i > new_value) && (tab_left_is_moving)); i -= 0.1) { gtk_adjustment_set_value(adj, i); while (g_main_pending()) g_main_iteration(TRUE); } gtk_adjustment_set_value(adj, new_value); tab_left_is_moving = 0; /* hSP: set to false in case we didnt get stopped (the normal case) */ } else { tab_left_is_moving = 0; /* hSP: jump directly to next element if user is clicking faster than we can scroll.. */ } } static void tab_scroll_right_down_clicked(GtkWidget *widget, chanview * cv) { GtkAdjustment *adj; gint viewport_size; gfloat new_value; GtkWidget *inner; gfloat i; inner = ((tabview *) cv)->inner; if (cv->vertical) { adj = gtk_viewport_get_vadjustment(GTK_VIEWPORT(inner->parent)); gdk_window_get_geometry(inner->parent->window, 0, 0, 0, &viewport_size, 0); } else { adj = gtk_viewport_get_hadjustment(GTK_VIEWPORT(inner->parent)); gdk_window_get_geometry(inner->parent->window, 0, 0, &viewport_size, 0, 0); } new_value = tab_search_offset(inner, adj->value, 1, cv->vertical); if (new_value == 0 || new_value + viewport_size > adj->upper) new_value = adj->upper - viewport_size; if (!tab_right_is_moving) { tab_right_is_moving = 1; for (i = adj->value; ((i < new_value) && (tab_right_is_moving)); i += 0.1) { gtk_adjustment_set_value(adj, i); while (g_main_pending()) g_main_iteration(TRUE); } gtk_adjustment_set_value(adj, new_value); tab_right_is_moving = 0; /* hSP: set to false in case we didnt get stopped (the normal case) */ } else { tab_right_is_moving = 0; /* hSP: jump directly to next element if user is clicking faster than we can scroll.. */ } } static gboolean tab_scroll_cb(GtkWidget *widget, GdkEventScroll * event, gpointer cv) { /* mouse wheel scrolling */ if (event->direction == GDK_SCROLL_UP) tab_scroll_left_up_clicked(widget, cv); else if (event->direction == GDK_SCROLL_DOWN) tab_scroll_right_down_clicked(widget, cv); return FALSE; } static void cv_tabs_xclick_cb(GtkWidget *button, chanview * cv) { cv->cb_xbutton(cv, cv->focused, cv->focused->tag, cv->focused->userdata); } /* make a Scroll (arrow) button */ static GtkWidget *make_sbutton(GtkArrowType type, void *click_cb, void *userdata) { GtkWidget *button, *arrow; button = gtk_button_new(); arrow = gtk_arrow_new(type, GTK_SHADOW_NONE); gtk_container_add(GTK_CONTAINER(button), arrow); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(click_cb), userdata); g_signal_connect(G_OBJECT(button), "scroll_event", G_CALLBACK(tab_scroll_cb), userdata); gtk_widget_show(arrow); return button; } /* only defined in ui-gtk-maingui.c */ GtkWidget *gtkutil_button(GtkWidget *box, char *stock, char *tip, void *callback, void *userdata, char *labeltext); static void cv_tabs_init(chanview * cv) { GtkWidget *box, *hbox = NULL; GtkWidget *viewport; GtkWidget *outer; GtkWidget *button; if (cv->vertical) outer = gtk_vbox_new(0, 0); else outer = gtk_hbox_new(0, 0); ((tabview *) cv)->outer = outer; g_signal_connect(G_OBJECT(outer), "size_allocate", G_CALLBACK(cv_tabs_sizealloc), cv); /* gtk_container_set_border_width (GTK_CONTAINER (outer), 2);*/ gtk_widget_show(outer); viewport = gtk_viewport_new(0, 0); gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); g_signal_connect(G_OBJECT(viewport), "size_request", G_CALLBACK(cv_tabs_sizerequest), cv); g_signal_connect(G_OBJECT(viewport), "scroll_event", G_CALLBACK(tab_scroll_cb), cv); gtk_box_pack_start(GTK_BOX(outer), viewport, 1, 1, 0); gtk_widget_show(viewport); if (cv->vertical) box = gtk_vbox_new(FALSE, 0); else box = gtk_hbox_new(FALSE, 0); ((tabview *) cv)->inner = box; gtk_container_add(GTK_CONTAINER(viewport), box); gtk_widget_show(box); /* if vertical, the buttons can be side by side */ if (cv->vertical) { hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(outer), hbox, 0, 0, 0); gtk_widget_show(hbox); } /* make the Scroll buttons */ ((tabview *) cv)->b2 = make_sbutton(cv->vertical ? GTK_ARROW_UP : GTK_ARROW_LEFT, tab_scroll_left_up_clicked, cv); ((tabview *) cv)->b1 = make_sbutton(cv->vertical ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, tab_scroll_right_down_clicked, cv); if (hbox) { gtk_container_add(GTK_CONTAINER(hbox), ((tabview *) cv)->b2); gtk_container_add(GTK_CONTAINER(hbox), ((tabview *) cv)->b1); } else { gtk_box_pack_start(GTK_BOX(outer), ((tabview *) cv)->b2, 0, 0, 0); gtk_box_pack_start(GTK_BOX(outer), ((tabview *) cv)->b1, 0, 0, 0); } button = gtkutil_button(outer, GTK_STOCK_CLOSE, NULL, cv_tabs_xclick_cb, cv, 0); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); gtk_container_add(GTK_CONTAINER(cv->box), outer); } static void cv_tabs_postinit(chanview * cv) { } static void tab_add_sorted(chanview * cv, GtkWidget *box, GtkWidget *tab, chan * ch) { GList *list; GtkBoxChild *child; int i = 0; void *b; if (!cv->sorted) { gtk_box_pack_start(GTK_BOX(box), tab, 0, 0, 0); gtk_widget_show(tab); return; } /* sorting TODO: * - move tab if renamed (dialogs) */ /* userdata, passed to mg_tabs_compare() */ b = ch->userdata; list = GTK_BOX(box)->children; while (list) { child = list->data; if (!GTK_IS_SEPARATOR(child->widget)) { void *a = g_object_get_data(G_OBJECT(child->widget), "u"); if (ch->tag == 0 && cv->cb_compare(a, b) > 0) { gtk_box_pack_start(GTK_BOX(box), tab, 0, 0, 0); gtk_box_reorder_child(GTK_BOX(box), tab, i); gtk_widget_show(tab); return; } } i++; list = list->next; } /* append */ gtk_box_pack_start(GTK_BOX(box), tab, 0, 0, 0); gtk_box_reorder_child(GTK_BOX(box), tab, i); gtk_widget_show(tab); } /* remove empty boxes and separators */ static void cv_tabs_prune(chanview * cv) { GList *boxes, *children; GtkWidget *box, *inner; GtkBoxChild *child; int empty; inner = ((tabview *) cv)->inner; boxes = GTK_BOX(inner)->children; while (boxes) { child = boxes->data; box = child->widget; boxes = boxes->next; /* check if the box is empty (except a vseperator) */ empty = TRUE; children = GTK_BOX(box)->children; while (children) { if (!GTK_IS_SEPARATOR(((GtkBoxChild *) children->data)->widget)) { empty = FALSE; break; } children = children->next; } if (empty) gtk_widget_destroy(box); } } static void tab_add_real(chanview * cv, GtkWidget *tab, chan * ch) { GList *boxes; GtkWidget *sep, *box, *inner; GtkBoxChild *child; inner = ((tabview *) cv)->inner; /* see if a family for this tab already exists */ boxes = GTK_BOX(inner)->children; if (boxes) { child = boxes->data; box = child->widget; tab_add_sorted(cv, box, tab, ch); gtk_widget_queue_resize(inner->parent); return; } /* create a new family box */ if (cv->vertical) { /* vertical */ box = gtk_vbox_new(FALSE, 0); sep = gtk_hseparator_new(); } else { /* horiz */ box = gtk_hbox_new(FALSE, 0); sep = gtk_vseparator_new(); } gtk_box_pack_end(GTK_BOX(box), sep, 0, 0, 4); gtk_widget_show(sep); gtk_box_pack_start(GTK_BOX(inner), box, 0, 0, 0); gtk_box_pack_start(GTK_BOX(box), tab, 0, 0, 0); gtk_widget_show(tab); gtk_widget_show(box); gtk_widget_queue_resize(inner->parent); } static gboolean tab_ignore_cb(GtkWidget *widget, GdkEventCrossing * event, gpointer user_data) { return TRUE; } /* called when a tab is clicked (button down) */ static void tab_pressed_cb(GtkToggleButton * tab, chan * ch) { chan *old_tab; int is_switching = TRUE; chanview *cv = ch->cv; ignore_toggle = TRUE; /* de-activate the old tab */ old_tab = cv->focused; if (old_tab && old_tab->impl) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(old_tab->impl), FALSE); if (old_tab == ch) is_switching = FALSE; } gtk_toggle_button_set_active(tab, TRUE); ignore_toggle = FALSE; cv->focused = ch; if ( /*tab->active */ is_switching) /* call the focus callback */ cv->cb_focus(cv, ch, ch->tag, ch->userdata); } /* called for keyboard tab toggles only */ static void tab_toggled_cb(GtkToggleButton * tab, chan * ch) { if (ignore_toggle) return; /* activated a tab via keyboard */ tab_pressed_cb(tab, ch); } static gboolean tab_click_cb(GtkWidget *wid, GdkEventButton * event, chan * ch) { return ch->cv->cb_contextmenu(ch->cv, ch, ch->tag, ch->userdata, event); } static void *cv_tabs_add(chanview * cv, chan * ch, char *name, GtkTreeIter * parent) { GtkWidget *but; but = gtk_toggle_button_new_with_label(name); gtk_widget_set_name(but, "xchat-tab"); g_object_set_data(G_OBJECT(but), "c", ch); /* used to trap right-clicks */ g_signal_connect(G_OBJECT(but), "button_press_event", G_CALLBACK(tab_click_cb), ch); /* avoid prelights */ g_signal_connect(G_OBJECT(but), "enter_notify_event", G_CALLBACK(tab_ignore_cb), NULL); g_signal_connect(G_OBJECT(but), "leave_notify_event", G_CALLBACK(tab_ignore_cb), NULL); g_signal_connect(G_OBJECT(but), "pressed", G_CALLBACK(tab_pressed_cb), ch); /* for keyboard */ g_signal_connect(G_OBJECT(but), "toggled", G_CALLBACK(tab_toggled_cb), ch); g_object_set_data(G_OBJECT(but), "u", ch->userdata); tab_add_real(cv, but, ch); return but; } static int tab_group_for_each_tab(chanview * cv, int (*callback) (GtkWidget *tab, int num, int usernum), int usernum) { GList *tabs; GList *boxes; GtkBoxChild *child; GtkBox *innerbox; int i; innerbox = (GtkBox *) ((tabview *) cv)->inner; boxes = innerbox->children; i = 0; while (boxes) { child = boxes->data; tabs = GTK_BOX(child->widget)->children; while (tabs) { child = tabs->data; if (!GTK_IS_SEPARATOR(child->widget)) { if (callback(child->widget, i, usernum) != -1) return i; i++; } tabs = tabs->next; } boxes = boxes->next; } return i; } static int tab_check_focus_cb(GtkWidget *tab, int num, int unused) { if (GTK_TOGGLE_BUTTON(tab)->active) return num; return -1; } /* returns the currently focused tab number */ static int tab_group_get_cur_page(chanview * cv) { return tab_group_for_each_tab(cv, tab_check_focus_cb, 0); } static void cv_tabs_focus(chan * ch) { if (ch->impl) /* focus the new one (tab_pressed_cb defocuses the old one) */ tab_pressed_cb(GTK_TOGGLE_BUTTON(ch->impl), ch); } static int tab_focus_num_cb(GtkWidget *tab, int num, int want) { if (num == want) { cv_tabs_focus(g_object_get_data(G_OBJECT(tab), "c")); return 1; } return -1; } static void cv_tabs_change_orientation(chanview * cv) { /* cleanup the old one */ if (cv->func_cleanup) cv->func_cleanup(cv); /* now rebuild a new tabbar or tree */ cv->func_init(cv); chanview_populate(cv); } /* switch to the tab number specified */ static void cv_tabs_move_focus(chanview * cv, gboolean relative, int num) { int i, max; if (relative) { max = cv->size; i = tab_group_get_cur_page(cv) + num; /* make it wrap around at both ends */ if (i < 0) i = max - 1; if (i >= max) i = 0; tab_group_for_each_tab(cv, tab_focus_num_cb, i); return; } tab_group_for_each_tab(cv, tab_focus_num_cb, num); } static void cv_tabs_remove(chan * ch) { gtk_widget_destroy(ch->impl); ch->impl = NULL; cv_tabs_prune(ch->cv); } static void cv_tabs_move(chan * ch, int delta) { int i, pos = 0; GList *list; GtkWidget *parent = ((GtkWidget *)ch->impl)->parent; i = 0; for (list = GTK_BOX(parent)->children; list; list = list->next) { GtkBoxChild *child_entry; child_entry = list->data; if (child_entry->widget == ch->impl) pos = i; i++; } pos = (pos - delta) % i; gtk_box_reorder_child(GTK_BOX(parent), ch->impl, pos); } static void cv_tabs_cleanup(chanview * cv) { if (cv->box) gtk_widget_destroy(((tabview *) cv)->outer); } static void cv_tabs_set_color(chan * ch, PangoAttrList * list) { gtk_label_set_attributes(GTK_LABEL(GTK_BIN(ch->impl)->child), list); } static void cv_tabs_rename(chan * ch, char *name) { PangoAttrList *attr; GtkWidget *tab = ch->impl; attr = gtk_label_get_attributes(GTK_LABEL(GTK_BIN(tab)->child)); if (attr) pango_attr_list_ref(attr); gtk_button_set_label(GTK_BUTTON(tab), name); gtk_widget_queue_resize(tab->parent->parent->parent); if (attr) { gtk_label_set_attributes(GTK_LABEL(GTK_BIN(tab)->child), attr); pango_attr_list_unref(attr); } } static gboolean cv_tabs_is_collapsed(chan * ch) { return FALSE; } static chan *cv_tabs_get_parent(chan * ch) { return NULL; } ekg-1.9~pre+r2855/src/ui-gtk-chanview-tree.c000066400000000000000000000215101174410337000205100ustar00rootroot00000000000000/* file included in chanview.c */ typedef struct { GtkTreeView *tree; GtkWidget *scrollw; /* scrolledWindow */ int idle_tag; } treeview; // #include "main.h" #define ui_quit 0 #define gui_tweaks_config 0 #if 0 #include "../common/xchat.h" #include "../common/xchatc.h" #include "fe-gtk.h" #include "maingui.h" #endif static void /* row-activated, when a row is double clicked */ cv_tree_activated_cb(GtkTreeView * view, GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) { if (gtk_tree_view_row_expanded(view, path)) gtk_tree_view_collapse_row(view, path); else gtk_tree_view_expand_row(view, path, FALSE); } static void /* row selected callback */ cv_tree_sel_cb(GtkTreeSelection * sel, chanview * cv) { GtkTreeModel *model; GtkTreeIter iter; chan *ch; if (gtk_tree_selection_get_selected(sel, &model, &iter)) { gtk_tree_model_get(model, &iter, COL_CHAN, &ch, -1); cv->focused = ch; cv->cb_focus(cv, ch, ch->tag, ch->userdata); } } static gboolean cv_tree_click_cb(GtkTreeView * tree, GdkEventButton * event, chanview * cv) { chan *ch; GtkTreeSelection *sel; GtkTreePath *path; GtkTreeIter iter; int ret = FALSE; if (event->button != 3 && event->state == 0) return FALSE; sel = gtk_tree_view_get_selection(tree); if (gtk_tree_view_get_path_at_pos(tree, event->x, event->y, &path, 0, 0, 0)) { if (event->button == 2) { gtk_tree_selection_unselect_all(sel); gtk_tree_selection_select_path(sel, path); } if (gtk_tree_model_get_iter(GTK_TREE_MODEL(cv->store), &iter, path)) { gtk_tree_model_get(GTK_TREE_MODEL(cv->store), &iter, COL_CHAN, &ch, -1); ret = cv->cb_contextmenu(cv, ch, ch->tag, ch->userdata, event); } gtk_tree_path_free(path); } return ret; } static void cv_tree_init(chanview * cv) { GtkWidget *view, *win; GtkCellRenderer *renderer; static const GtkTargetEntry dnd_src_target[] = { {"XCHAT_CHANVIEW", GTK_TARGET_SAME_APP, 75} }; static const GtkTargetEntry dnd_dest_target[] = { {"XCHAT_USERLIST", GTK_TARGET_SAME_APP, 75} }; win = gtk_scrolled_window_new(0, 0); /*gtk_container_set_border_width (GTK_CONTAINER (win), 1); */ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(win), GTK_SHADOW_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(cv->box), win); gtk_widget_show(win); view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(cv->store)); gtk_widget_set_name(view, "xchat-tree"); if (cv->style) gtk_widget_set_style(view, cv->style); /*gtk_widget_modify_base (view, GTK_STATE_NORMAL, &colors[COL_BG]); */ GTK_WIDGET_UNSET_FLAGS(view, GTK_CAN_FOCUS); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); #if GTK_CHECK_VERSION(2,10,0) if (!(gui_tweaks_config & 8)) gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(view), TRUE); #endif gtk_container_add(GTK_CONTAINER(win), view); /* icon column */ if (cv->use_icons) { renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL, renderer, "pixbuf", COL_PIXBUF, NULL); } /* main column */ renderer = gtk_cell_renderer_text_new(); gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL, renderer, "text", COL_NAME, "attributes", COL_ATTR, NULL); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(view))), "changed", G_CALLBACK(cv_tree_sel_cb), cv); g_signal_connect(G_OBJECT(view), "button-press-event", G_CALLBACK(cv_tree_click_cb), cv); g_signal_connect(G_OBJECT(view), "row-activated", G_CALLBACK(cv_tree_activated_cb), NULL); gtk_drag_dest_set(view, GTK_DEST_DEFAULT_ALL, dnd_dest_target, 1, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); gtk_drag_source_set(view, GDK_BUTTON1_MASK, dnd_src_target, 1, GDK_ACTION_COPY); #ifdef DARK g_signal_connect(G_OBJECT(view), "drag_begin", G_CALLBACK(mg_drag_begin_cb), NULL); g_signal_connect(G_OBJECT(view), "drag_drop", G_CALLBACK(mg_drag_drop_cb), NULL); g_signal_connect(G_OBJECT(view), "drag_motion", G_CALLBACK(mg_drag_motion_cb), NULL); g_signal_connect(G_OBJECT(view), "drag_end", G_CALLBACK(mg_drag_end_cb), NULL); #endif ((treeview *) cv)->tree = GTK_TREE_VIEW(view); ((treeview *) cv)->scrollw = win; ((treeview *) cv)->idle_tag = 0; gtk_widget_show(view); } static void cv_tree_postinit(chanview * cv) { gtk_tree_view_expand_all(((treeview *) cv)->tree); } static void *cv_tree_add(chanview * cv, chan * ch, char *name, GtkTreeIter * parent) { GtkTreePath *path; if (parent) { /* expand the parent node */ path = gtk_tree_model_get_path(GTK_TREE_MODEL(cv->store), parent); if (path) { gtk_tree_view_expand_row(((treeview *) cv)->tree, path, FALSE); gtk_tree_path_free(path); } } return NULL; } static void cv_tree_change_orientation(chanview * cv) { } static void cv_tree_focus(chan * ch) { GtkTreeView *tree = ((treeview *) ch->cv)->tree; GtkTreeModel *model = gtk_tree_view_get_model(tree); GtkTreePath *path; GtkTreeIter parent; /* expand the parent node */ if (gtk_tree_model_iter_parent(model, &parent, &ch->iter)) { path = gtk_tree_model_get_path(model, &parent); if (path) { /*if (!gtk_tree_view_row_expanded (tree, path)) { gtk_tree_path_free (path); return; } */ gtk_tree_view_expand_row(tree, path, FALSE); gtk_tree_path_free(path); } } path = gtk_tree_model_get_path(model, &ch->iter); if (path) { gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, 0.5, 0.5); gtk_tree_view_set_cursor(tree, path, NULL, FALSE); gtk_tree_path_free(path); } } static void cv_tree_move_focus(chanview * cv, gboolean relative, int num) { chan *ch; if (relative) { num += cv_find_number_of_chan(cv, cv->focused); num %= cv->size; /* make it wrap around at both ends */ if (num < 0) num = cv->size - 1; } ch = cv_find_chan_by_number(cv, num); if (ch) cv_tree_focus(ch); } /*static gboolean cv_timeout (chanview *cv) { int colnum = cv->use_icons ? 1 : 0; GtkTreeViewColumn *col; col = gtk_tree_view_get_column (GTK_TREE_VIEW (((treeview *)cv)->tree), colnum); gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY); ((treeview *)cv)->idle_tag = 0; return FALSE; }*/ static void cv_tree_remove(chan * ch) { /* chanview *cv = ch->cv; int colnum = cv->use_icons ? 1 : 0; GtkTreeViewColumn *col = gtk_tree_view_get_column (GTK_TREE_VIEW (((treeview *)cv)->tree), colnum); gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE); if (((treeview *)cv)->idle_tag == 0) ((treeview *)cv)->idle_tag = g_idle_add ((GSourceFunc)cv_timeout, cv);*/ } static void move_row(chan * ch, int delta, GtkTreeIter * parent) { GtkTreeStore *store = ch->cv->store; GtkTreeIter *src = &ch->iter; GtkTreeIter dest = ch->iter; GtkTreePath *dest_path; if (delta < 0) { /* down */ if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &dest)) gtk_tree_store_swap(store, src, &dest); else /* move to top */ gtk_tree_store_move_after(store, src, NULL); } else { dest_path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &dest); if (gtk_tree_path_prev(dest_path)) { gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &dest, dest_path); gtk_tree_store_swap(store, src, &dest); } else { /* move to bottom */ gtk_tree_store_move_before(store, src, NULL); } gtk_tree_path_free(dest_path); } } static void cv_tree_move(chan * ch, int delta) { GtkTreeIter parent; /* do nothing if this is a server row */ if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(ch->cv->store), &parent, &ch->iter)) move_row(ch, delta, &parent); } static void cv_tree_cleanup(chanview * cv) { if (((treeview *) cv)->idle_tag) { g_source_remove(((treeview *) cv)->idle_tag); ((treeview *) cv)->idle_tag = 0; } if (cv->box) /* kill the scrolled window */ gtk_widget_destroy(((treeview *) cv)->scrollw); } static void cv_tree_set_color(chan * ch, PangoAttrList * list) { /* nothing to do, it's already set in the store */ } static void cv_tree_rename(chan * ch, char *name) { /* nothing to do, it's already renamed in the store */ } static chan *cv_tree_get_parent(chan * ch) { chan *parent_ch = NULL; GtkTreeIter parent; if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(ch->cv->store), &parent, &ch->iter)) { gtk_tree_model_get(GTK_TREE_MODEL(ch->cv->store), &parent, COL_CHAN, &parent_ch, -1); } return parent_ch; } static gboolean cv_tree_is_collapsed(chan * ch) { chan *parent = cv_tree_get_parent(ch); GtkTreePath *path = NULL; gboolean ret; if (parent == NULL) return FALSE; path = gtk_tree_model_get_path(GTK_TREE_MODEL(parent->cv->store), &parent->iter); ret = !gtk_tree_view_row_expanded(((treeview *) parent->cv)->tree, path); gtk_tree_path_free(path); return ret; } ekg-1.9~pre+r2855/src/ui-gtk-chanview.c000066400000000000000000000307351174410337000175640ustar00rootroot00000000000000/* abstract channel view: tabs or tree or anything you like */ #include #include #include #include "ui-gtk-chanview.h" // #include "ui-gtk-gtkutil.h" /* treeStore columns */ #define COL_NAME 0 /* (char *) */ #define COL_CHAN 1 /* (chan *) */ #define COL_ATTR 2 /* (PangoAttrList *) */ #define COL_PIXBUF 3 /* (GdkPixbuf *) */ struct _chanview { /* impl scratch area */ char implscratch[sizeof (void *) * 8]; GtkTreeStore *store; int size; /* number of channels in view */ GtkWidget *box; /* the box we destroy when changing implementations */ GtkStyle *style; /* style used for tree */ chan *focused; /* currently focused channel */ int trunc_len; /* callbacks */ void (*cb_focus) (chanview *, chan *, int tag, void *userdata); void (*cb_xbutton) (chanview *, chan *, int tag, void *userdata); gboolean (*cb_contextmenu) (chanview *, chan *, int tag, void *userdata, GdkEventButton *); int (*cb_compare) (void *a, void *b); /* impl */ void (*func_init) (chanview *); void (*func_postinit) (chanview *); void *(*func_add) (chanview *, chan *, char *, GtkTreeIter *); void (*func_move_focus) (chanview *, gboolean, int); void (*func_change_orientation) (chanview *); void (*func_remove) (chan *); void (*func_move) (chan *, int delta); void (*func_focus) (chan *); void (*func_set_color) (chan *, PangoAttrList *); void (*func_rename) (chan *, char *); gboolean (*func_is_collapsed) (chan *); chan *(*func_get_parent) (chan *); void (*func_cleanup) (chanview *); unsigned int sorted:1; unsigned int vertical:1; unsigned int use_icons:1; }; struct _chan { chanview *cv; /* our owner */ GtkTreeIter iter; void *userdata; /* session * */ void *impl; /* togglebutton or null */ GdkPixbuf *icon; short allow_closure; /* allow it to be closed when it still has children? */ short tag; }; static chan *cv_find_chan_by_number (chanview *cv, int num); static int cv_find_number_of_chan (chanview *cv, chan *find_ch); /* ======= TABS ======= */ #include "ui-gtk-chanview-tabs.c" /* ======= TREE ======= */ #include "ui-gtk-chanview-tree.c" /* ==== ABSTRACT CHANVIEW ==== */ static char * truncate_tab_name (char *name, int max) { char *buf; if (max > 2 && g_utf8_strlen (name, -1) > max) { /* truncate long channel names */ buf = malloc (strlen (name) + 4); strcpy (buf, name); g_utf8_offset_to_pointer (buf, max)[0] = 0; strcat (buf, ".."); return buf; } return name; } /* iterate through a model, into 1 depth of children */ static void model_foreach_1 (GtkTreeModel *model, void (*func)(void *, GtkTreeIter *), void *userdata) { GtkTreeIter iter, inner; if (gtk_tree_model_get_iter_first (model, &iter)) { do { func (userdata, &iter); if (gtk_tree_model_iter_children (model, &inner, &iter)) { do func (userdata, &inner); while (gtk_tree_model_iter_next (model, &inner)); } } while (gtk_tree_model_iter_next (model, &iter)); } } static void chanview_pop_cb (chanview *cv, GtkTreeIter *iter) { chan *ch; char *name; PangoAttrList *attr; gtk_tree_model_get (GTK_TREE_MODEL (cv->store), iter, COL_NAME, &name, COL_CHAN, &ch, COL_ATTR, &attr, -1); ch->impl = cv->func_add (cv, ch, name, NULL); if (attr) { cv->func_set_color (ch, attr); pango_attr_list_unref (attr); } g_free (name); } static void chanview_populate (chanview *cv) { model_foreach_1 (GTK_TREE_MODEL (cv->store), (void *)chanview_pop_cb, cv); } void chanview_set_impl (chanview *cv, int type) { /* cleanup the old one */ if (cv->func_cleanup) cv->func_cleanup (cv); switch (type) { case 0: cv->func_init = cv_tabs_init; cv->func_postinit = cv_tabs_postinit; cv->func_add = cv_tabs_add; cv->func_move_focus = cv_tabs_move_focus; cv->func_change_orientation = cv_tabs_change_orientation; cv->func_remove = cv_tabs_remove; cv->func_move = cv_tabs_move; cv->func_focus = cv_tabs_focus; cv->func_set_color = cv_tabs_set_color; cv->func_rename = cv_tabs_rename; cv->func_is_collapsed = cv_tabs_is_collapsed; cv->func_get_parent = cv_tabs_get_parent; cv->func_cleanup = cv_tabs_cleanup; break; default: cv->func_init = cv_tree_init; cv->func_postinit = cv_tree_postinit; cv->func_add = cv_tree_add; cv->func_move_focus = cv_tree_move_focus; cv->func_change_orientation = cv_tree_change_orientation; cv->func_remove = cv_tree_remove; cv->func_move = cv_tree_move; cv->func_focus = cv_tree_focus; cv->func_set_color = cv_tree_set_color; cv->func_rename = cv_tree_rename; cv->func_is_collapsed = cv_tree_is_collapsed; cv->func_get_parent = cv_tree_get_parent; cv->func_cleanup = cv_tree_cleanup; break; } /* now rebuild a new tabbar or tree */ cv->func_init (cv); chanview_populate (cv); cv->func_postinit (cv); /* force re-focus */ if (cv->focused) cv->func_focus (cv->focused); } static void chanview_free_ch (chanview *cv, GtkTreeIter *iter) { chan *ch; gtk_tree_model_get (GTK_TREE_MODEL (cv->store), iter, COL_CHAN, &ch, -1); free (ch); } static void chanview_destroy_store (chanview *cv) /* free every (chan *) in the store */ { model_foreach_1 (GTK_TREE_MODEL (cv->store), (void *)chanview_free_ch, cv); g_object_unref (cv->store); } static void chanview_destroy (chanview *cv) { if (cv->func_cleanup) cv->func_cleanup (cv); if (cv->box) gtk_widget_destroy (cv->box); chanview_destroy_store (cv); free (cv); } static void chanview_box_destroy_cb (GtkWidget *box, chanview *cv) { cv->box = NULL; chanview_destroy (cv); } chanview * chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, GtkStyle *style) { chanview *cv; cv = calloc (1, sizeof (chanview)); cv->store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF); cv->style = style; cv->box = gtk_hbox_new (0, 0); cv->trunc_len = trunc_len; cv->sorted = sort; cv->use_icons = use_icons; gtk_widget_show (cv->box); chanview_set_impl (cv, type); g_signal_connect (G_OBJECT (cv->box), "destroy", G_CALLBACK (chanview_box_destroy_cb), cv); return cv; } /* too lazy for signals */ void chanview_set_callbacks (chanview *cv, void (*cb_focus) (chanview *, chan *, int tag, void *userdata), void (*cb_xbutton) (chanview *, chan *, int tag, void *userdata), gboolean (*cb_contextmenu) (chanview *, chan *, int tag, void *userdata, GdkEventButton *), int (*cb_compare) (void *a, void *b)) { cv->cb_focus = cb_focus; cv->cb_xbutton = cb_xbutton; cv->cb_contextmenu = cb_contextmenu; cv->cb_compare = cb_compare; } static chan * chanview_add_real (chanview *cv, char *name, void *userdata, gboolean allow_closure, int tag, GdkPixbuf *icon, chan *ch, chan *avoid) { GtkTreeIter parent_iter; GtkTreeIter iter; gboolean has_parent = FALSE; gtk_tree_store_append (cv->store, &iter, NULL); if (!ch) { ch = calloc (1, sizeof (chan)); ch->userdata = userdata; ch->cv = cv; ch->allow_closure = allow_closure; ch->tag = tag; ch->icon = icon; } memcpy (&(ch->iter), &iter, sizeof (iter)); gtk_tree_store_set (cv->store, &iter, COL_NAME, name, COL_CHAN, ch, COL_PIXBUF, icon, -1); cv->size++; if (!has_parent) ch->impl = cv->func_add (cv, ch, name, NULL); else ch->impl = cv->func_add (cv, ch, name, &parent_iter); return ch; } chan * chanview_add (chanview *cv, char *name, void *userdata, gboolean allow_closure, int tag, GdkPixbuf *icon) { char *new_name; chan *ret; new_name = truncate_tab_name (name, cv->trunc_len); ret = chanview_add_real (cv, new_name, userdata, allow_closure, tag, icon, NULL, NULL); if (new_name != name) free (new_name); return ret; } int chanview_get_size (chanview *cv) { return cv->size; } GtkWidget * chanview_get_box (chanview *cv) { return cv->box; } void chanview_move_focus (chanview *cv, gboolean relative, int num) { cv->func_move_focus (cv, relative, num); } GtkOrientation chanview_get_orientation (chanview *cv) { return (cv->vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL); } void chanview_set_orientation (chanview *cv, gboolean vertical) { if (vertical != cv->vertical) { cv->vertical = vertical; cv->func_change_orientation (cv); } } int chan_get_tag (chan *ch) { return ch->tag; } void * chan_get_userdata (chan *ch) { return ch->userdata; } void chan_focus (chan *ch) { if (ch->cv->focused == ch) return; ch->cv->func_focus (ch); } void chan_move (chan *ch, int delta) { ch->cv->func_move (ch, delta); } void chan_set_color (chan *ch, PangoAttrList *list) { gtk_tree_store_set (ch->cv->store, &ch->iter, COL_ATTR, list, -1); ch->cv->func_set_color (ch, list); } void chan_rename (chan *ch, char *name, int trunc_len) { char *new_name; new_name = truncate_tab_name (name, trunc_len); gtk_tree_store_set (ch->cv->store, &ch->iter, COL_NAME, new_name, -1); ch->cv->func_rename (ch, new_name); ch->cv->trunc_len = trunc_len; if (new_name != name) free (new_name); } /* this thing is overly complicated */ static int cv_find_number_of_chan (chanview *cv, chan *find_ch) { GtkTreeIter iter, inner; chan *ch; int i = 0; if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cv->store), &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1); if (ch == find_ch) return i; i++; if (gtk_tree_model_iter_children (GTK_TREE_MODEL (cv->store), &inner, &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &inner, COL_CHAN, &ch, -1); if (ch == find_ch) return i; i++; } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &inner)); } } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &iter)); } return 0; /* WARNING */ } /* this thing is overly complicated too */ static chan * cv_find_chan_by_number (chanview *cv, int num) { GtkTreeIter iter, inner; chan *ch; int i = 0; if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cv->store), &iter)) { do { if (i == num) { gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1); return ch; } i++; if (gtk_tree_model_iter_children (GTK_TREE_MODEL (cv->store), &inner, &iter)) { do { if (i == num) { gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &inner, COL_CHAN, &ch, -1); return ch; } i++; } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &inner)); } } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &iter)); } return NULL; } static void chan_emancipate_children (chan *ch) { char *name; chan *childch; GtkTreeIter childiter; PangoAttrList *attr; while (gtk_tree_model_iter_children (GTK_TREE_MODEL (ch->cv->store), &childiter, &ch->iter)) { /* remove and re-add all the children, but avoid using "ch" as parent */ gtk_tree_model_get (GTK_TREE_MODEL (ch->cv->store), &childiter, COL_NAME, &name, COL_CHAN, &childch, COL_ATTR, &attr, -1); ch->cv->func_remove (childch); gtk_tree_store_remove (ch->cv->store, &childiter); ch->cv->size--; chanview_add_real (childch->cv, name, childch->userdata, childch->allow_closure, childch->tag, childch->icon, childch, ch); if (attr) { childch->cv->func_set_color (childch, attr); pango_attr_list_unref (attr); } g_free (name); } } gboolean chan_remove (chan *ch, gboolean force) { chan *new_ch; int i, num; if (ui_quit) /* avoid lots of looping on exit */ return TRUE; /* is this ch allowed to be closed while still having children? */ if (!force && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (ch->cv->store), &ch->iter) && !ch->allow_closure) return FALSE; chan_emancipate_children (ch); ch->cv->func_remove (ch); /* is it the focused one? */ if (ch->cv->focused == ch) { ch->cv->focused = NULL; /* try to move the focus to some other valid channel */ num = cv_find_number_of_chan (ch->cv, ch); /* move to the one left of the closing tab */ new_ch = cv_find_chan_by_number (ch->cv, num - 1); if (new_ch && new_ch != ch) { chan_focus (new_ch); /* this'll will set ch->cv->focused for us too */ } else { /* if it fails, try focus from tab 0 and up */ for (i = 0; i < ch->cv->size; i++) { new_ch = cv_find_chan_by_number (ch->cv, i); if (new_ch && new_ch != ch) { chan_focus (new_ch); /* this'll will set ch->cv->focused for us too */ break; } } } } ch->cv->size--; gtk_tree_store_remove (ch->cv->store, &ch->iter); free (ch); return TRUE; } gboolean chan_is_collapsed (chan *ch) { return ch->cv->func_is_collapsed (ch); } chan * chan_get_parent (chan *ch) { return ch->cv->func_get_parent (ch); } ekg-1.9~pre+r2855/src/ui-gtk-chanview.h000066400000000000000000000025161174410337000175650ustar00rootroot00000000000000 typedef struct _chanview chanview; typedef struct _chan chan; chanview *chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, GtkStyle *style); void chanview_set_callbacks (chanview *cv, void (*cb_focus) (chanview *, chan *, int tag, void *userdata), void (*cb_xbutton) (chanview *, chan *, int tag, void *userdata), gboolean (*cb_contextmenu) (chanview *, chan *, int tag, void *userdata, GdkEventButton *), int (*cb_compare) (void *a, void *b)); void chanview_set_impl (chanview *cv, int type); chan *chanview_add (chanview *cv, char *name, void *userdata, gboolean allow_closure, int tag, GdkPixbuf *icon); int chanview_get_size (chanview *cv); GtkWidget *chanview_get_box (chanview *cv); void chanview_move_focus (chanview *cv, gboolean relative, int num); GtkOrientation chanview_get_orientation (chanview *cv); void chanview_set_orientation (chanview *cv, gboolean vertical); int chan_get_tag (chan *ch); void *chan_get_userdata (chan *ch); void chan_focus (chan *ch); void chan_move (chan *ch, int delta); void chan_set_color (chan *ch, PangoAttrList *list); void chan_rename (chan *ch, char *new_name, int trunc_len); gboolean chan_remove (chan *ch, gboolean force); gboolean chan_is_collapsed (chan *ch); chan * chan_get_parent (chan *ch); #define FOCUS_NEW_ALL 1 #define FOCUS_NEW_ONLY_ASKED 2 #define FOCUS_NEW_NONE 0 ekg-1.9~pre+r2855/src/ui-gtk-maingui.c000066400000000000000000003557401174410337000174170ustar00rootroot00000000000000/* X-Chat * Copyright (C) 1998-2007 Peter Zelezny. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * port to ekg2 && ekg: * Copyright (C) 2007 Jakub Zawadzki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ // #define GTK_DISABLE_DEPRECATED #define USE_XLIB #include #include #include #include #include #include /* for inet_ntoa() */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libgadu.h" /* potrzebne dla stalych ze stanami */ #include "comptime.h" #include "commands.h" #include "userlist.h" #include "xmalloc.h" #include "ui.h" #include "ui-gtk.h" #include "ui-gtk-xtext.h" #include "ui-gtk-palette.h" // #include "menu.h" #include "ui-gtk-chanview.h" // #include "ui-gtk-bindings.h" // #include "ui-gtk-userlistgui.h" /* extern */ void fe_userlist_numbers(window_t *sess); void fe_userlist_insert(window_t *sess, struct userlist *u); /* forward */ void mg_changui_new(window_t *sess, int tab, int focus); void mg_open_quit_dialog(gboolean minimize_button); static void mg_detach(window_t *sess, int mode); void mg_decide_userlist(window_t *sess, gboolean switch_to_current); void mg_change_layout(int type); #if 0 #include "../common/xchat.h" #include "../common/fe.h" #include "../common/server.h" #include "../common/xchatc.h" #include "../common/outbound.h" #include "../common/inbound.h" #include "../common/plugin.h" #include "../common/modes.h" #include "../common/url.h" #include "fe-gtk.h" #include "banlist.h" #include "joind.h" #include "maingui.h" #include "pixmaps.h" #include "plugin-tray.h" #endif /* XXX */ #define MENU_ID_AWAY 1 #define MENU_ID_MENUBAR 2 #define MENU_ID_TOPICBAR 3 #define MENU_ID_USERLIST 4 #define MENU_ID_ULBUTTONS 5 #define MENU_ID_MODEBUTTONS 6 #define MENU_ID_LAYOUT_TABS 7 #define MENU_ID_LAYOUT_TREE 8 #define MENU_ID_DISCONNECT 9 #define MENU_ID_RECONNECT 10 #define MENU_ID_JOIN 11 #define MENU_ID_USERMENU 12 #if (MENU_ID_NUM < MENU_ID_USERMENU) #error MENU_ID_NUM is set wrong #endif struct window; /* forward */ #define GUI_SPACING (3) #define GUI_BORDER (0) #define SCROLLBAR_SPACING (2) /* two different types of tabs */ #define TAG_WINDOW 0 /* normal ekg window */ #define TAG_UTIL 1 /* dcc, notify, chanlist */ static void mg_link_irctab(struct window *sess, int focus); static void mg_create_entry(struct window *sess, GtkWidget *box); static gtk_window_ui_t static_mg_gui; static gtk_window_ui_t *mg_gui = NULL; /* the shared irc tab */ GtkWidget *parent_window = NULL; /* the master window */ GtkStyle *input_style; static chan *active_tab = NULL; /* active tab */ static PangoAttrList *away_list; static PangoAttrList *newdata_list; static PangoAttrList *nickseen_list; static PangoAttrList *newmsg_list; static PangoAttrList *plain_list = NULL; enum { USERLIST_STATUS = 0, USERLIST_UIN, USERLIST_NICKNAME, USERLIST_DESCRIPTION, USERLIST_USER, USERLIST_COLOR, USERLIST_COLS }; static int contacts_order[5] = { 0, 1, 2, 3, 4 /* -1 */ }; #define show_descr_in_userlist_config 0 /* XXX!!! */ /* REMOVED: * userlist_select() ->> select a row in the userlist by nick-name * fe_uselect() * fe_userlist_set_selected() */ /************************************************* MENU *****************************/ static GSList *submenu_list; enum { M_MENUITEM, M_NEWMENU, M_END, M_SEP, M_MENUTOG, M_MENURADIO, M_MENUSTOCK, M_MENUPIX, M_MENUSUB }; struct mymenu { char *text; void *callback; char *image; unsigned char type; /* M_XXX */ unsigned char id; /* MENU_ID_XXX (menu.h) */ unsigned char state; /* ticked or not? */ unsigned char sensitive; /* shaded out? */ guint key; /* GDK_x */ }; #define XCMENU_DOLIST 1 #define XCMENU_SHADED 1 #define XCMENU_MARKUP 2 #define XCMENU_MNEMONIC 4 #if 0 /* execute a userlistbutton/popupmenu command */ static void nick_command(session *sess, char *cmd) { if (*cmd == '!') xchat_exec(cmd + 1); else handle_command(sess, cmd, TRUE); } /* fill in the %a %s %n etc and execute the command */ void nick_command_parse(session *sess, char *cmd, char *nick, char *allnick) { char *buf; char *host = _("Host unknown"); struct User *user; int len; /* if (sess->type == SESS_DIALOG) { buf = (char *)(GTK_ENTRY (sess->gui->topic_entry)->text); buf = strrchr (buf, '@'); if (buf) host = buf + 1; } else*/ { user = userlist_find(sess, nick); if (user && user->hostname) host = strchr(user->hostname, '@') + 1; } /* this can't overflow, since popup->cmd is only 256 */ len = strlen(cmd) + strlen(nick) + strlen(allnick) + 512; buf = malloc(len); auto_insert(buf, len, cmd, 0, 0, allnick, sess->channel, "", server_get_network(sess->server, TRUE), host, sess->server->nick, nick); nick_command(sess, buf); free(buf); } /* userlist button has been clicked */ void userlist_button_cb(GtkWidget *button, char *cmd) { int i, num_sel, using_allnicks = FALSE; char **nicks, *allnicks; char *nick = NULL; session *sess; sess = current_sess; if (strstr(cmd, "%a")) using_allnicks = TRUE; if (sess->type == SESS_DIALOG) { /* fake a selection */ nicks = malloc(sizeof(char *) * 2); nicks[0] = g_strdup(sess->channel); nicks[1] = NULL; num_sel = 1; } else { /* find number of selected rows */ nicks = userlist_selection_list(sess->gui->user_tree, &num_sel); if (num_sel < 1) { nick_command_parse(sess, cmd, "", ""); return; } } /* create "allnicks" string */ allnicks = malloc(((NICKLEN + 1) * num_sel) + 1); *allnicks = 0; i = 0; while (nicks[i]) { if (i > 0) strcat(allnicks, " "); strcat(allnicks, nicks[i]); if (!nick) nick = nicks[0]; /* if not using "%a", execute the command once for each nickname */ if (!using_allnicks) nick_command_parse(sess, cmd, nicks[i], ""); i++; } if (using_allnicks) { if (!nick) nick = ""; nick_command_parse(sess, cmd, nick, allnicks); } while (num_sel) { num_sel--; g_free(nicks[num_sel]); } free(nicks); free(allnicks); } #endif /* a popup-menu-item has been selected */ static void popup_menu_cb(GtkWidget *item, char *cmd) { char *nick; /* the userdata is set in menu_quick_item() */ nick = g_object_get_data(G_OBJECT(item), "u"); #if 0 if (!nick) { /* userlist popup menu */ /* treat it just like a userlist button */ userlist_button_cb(NULL, cmd); return; } if (!current_sess) /* for url grabber window */ nick_command_parse(sess_list->data, cmd, nick, nick); else nick_command_parse(current_sess, cmd, nick, nick); #endif } #if 0 GtkWidget *menu_toggle_item(char *label, GtkWidget *menu, void *callback, void *userdata, int state) { GtkWidget *item; item = gtk_check_menu_item_new_with_label(label); gtk_check_menu_item_set_active((GtkCheckMenuItem *) item, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(callback), userdata); gtk_widget_show(item); return item; } #endif static GtkWidget * menu_quick_item(char *cmd, char *label, GtkWidget *menu, int flags, gpointer userdata, char *icon) { GtkWidget *img, *item; if (!label) item = gtk_menu_item_new(); else { if (icon) { /*if (flags & XCMENU_MARKUP) item = gtk_image_menu_item_new_with_markup (label); else */ item = gtk_image_menu_item_new_with_mnemonic(label); img = gtk_image_new_from_file(icon); if (img) gtk_image_menu_item_set_image((GtkImageMenuItem *) item, img); else { img = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_MENU); if (img) gtk_image_menu_item_set_image((GtkImageMenuItem *) item, img); } } else { if (flags & XCMENU_MARKUP) { item = gtk_menu_item_new_with_label(""); if (flags & XCMENU_MNEMONIC) gtk_label_set_markup_with_mnemonic(GTK_LABEL (GTK_BIN(item)->child), label); else gtk_label_set_markup(GTK_LABEL(GTK_BIN(item)->child), label); } else { if (flags & XCMENU_MNEMONIC) item = gtk_menu_item_new_with_mnemonic(label); else item = gtk_menu_item_new_with_label(label); } } } gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_object_set_data(G_OBJECT(item), "u", userdata); if (cmd) g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(popup_menu_cb), cmd); if (flags & XCMENU_SHADED) gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE); gtk_widget_show_all(item); return item; } static void menu_quick_item_with_callback(void *callback, char *label, GtkWidget *menu, void *arg) { GtkWidget *item; item = gtk_menu_item_new_with_label(label); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(callback), arg); gtk_widget_show(item); } static GtkWidget *menu_quick_sub(char *name, GtkWidget *menu, GtkWidget **sub_item_ret, int flags, int pos) { GtkWidget *sub_menu; GtkWidget *sub_item; if (!name) return menu; /* Code to add a submenu */ sub_menu = gtk_menu_new(); if (flags & XCMENU_MARKUP) { sub_item = gtk_menu_item_new_with_label(""); gtk_label_set_markup(GTK_LABEL(GTK_BIN(sub_item)->child), name); } else { if (flags & XCMENU_MNEMONIC) sub_item = gtk_menu_item_new_with_mnemonic(name); else sub_item = gtk_menu_item_new_with_label(name); } gtk_menu_shell_insert(GTK_MENU_SHELL(menu), sub_item, pos); gtk_widget_show(sub_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(sub_item), sub_menu); if (sub_item_ret) *sub_item_ret = sub_item; if (flags & XCMENU_DOLIST) /* We create a new element in the list */ submenu_list = g_slist_prepend(submenu_list, sub_menu); return sub_menu; } static GtkWidget *menu_quick_endsub() { /* Just delete the first element in the linked list pointed to by first */ if (submenu_list) submenu_list = g_slist_remove(submenu_list, submenu_list->data); if (submenu_list) return (submenu_list->data); else return NULL; } #if 0 static void toggle_cb(GtkWidget *item, char *pref_name) { char buf[256]; if (GTK_CHECK_MENU_ITEM(item)->active) snprintf(buf, sizeof(buf), "set %s 1", pref_name); else snprintf(buf, sizeof(buf), "set %s 0", pref_name); handle_command(current_sess, buf, FALSE); } static int is_in_path(char *cmd) { char *prog = strdup(cmd + 1); /* 1st char is "!" */ char *space, *path, *orig; orig = prog; /* save for free()ing */ /* special-case these default entries. */ /* 123456789012345678 */ if (strncmp(prog, "gnome-terminal -x ", 18) == 0) /* don't check for gnome-terminal, but the thing it's executing! */ prog += 18; space = strchr(prog, ' '); /* this isn't 100% but good enuf */ if (space) *space = 0; path = g_find_program_in_path(prog); if (path) { g_free(path); g_free(orig); return 1; } g_free(orig); return 0; } /* append items to "menu" using the (struct popup*) list provided */ void menu_create(GtkWidget *menu, GSList * list, char *target, int check_path) { struct popup *pop; GtkWidget *tempmenu = menu, *subitem = NULL; int childcount = 0; submenu_list = g_slist_prepend(0, menu); while (list) { pop = (struct popup *)list->data; if (!strncasecmp(pop->name, "SUB", 3)) { childcount = 0; tempmenu = menu_quick_sub(pop->cmd, tempmenu, &subitem, XCMENU_DOLIST, -1); } else if (!strncasecmp(pop->name, "TOGGLE", 6)) { childcount++; menu_toggle_item(pop->name + 7, tempmenu, toggle_cb, pop->cmd, cfg_get_bool(pop->cmd)); } else if (!strncasecmp(pop->name, "ENDSUB", 6)) { /* empty sub menu due to no programs in PATH? */ if (check_path && childcount < 1) gtk_widget_destroy(subitem); subitem = NULL; if (tempmenu != menu) tempmenu = menu_quick_endsub(); /* If we get here and tempmenu equals menu that means we havent got any submenus to exit from */ } else if (!strncasecmp(pop->name, "SEP", 3)) { menu_quick_item(0, 0, tempmenu, XCMENU_SHADED, 0, 0); } else { if (!check_path || pop->cmd[0] != '!') { menu_quick_item(pop->cmd, pop->name, tempmenu, 0, target, 0); /* check if the program is in path, if not, leave it out! */ } else if (is_in_path(pop->cmd)) { childcount++; menu_quick_item(pop->cmd, pop->name, tempmenu, 0, target, 0); } } list = list->next; } /* Let's clean up the linked list from mem */ while (submenu_list) submenu_list = g_slist_remove(submenu_list, submenu_list->data); } #endif static void menu_destroy(GtkWidget *menu, gpointer objtounref) { gtk_widget_destroy(menu); g_object_unref(menu); if (objtounref) g_object_unref(G_OBJECT(objtounref)); } static void menu_popup(GtkWidget *menu, GdkEventButton * event, gpointer objtounref) { #if (GTK_MAJOR_VERSION != 2) || (GTK_MINOR_VERSION != 0) if (event && event->window) gtk_menu_set_screen(GTK_MENU(menu), gdk_drawable_get_screen(event->window)); #endif g_object_ref(menu); g_object_ref_sink(menu); g_object_unref(menu); g_signal_connect(G_OBJECT(menu), "selection-done", G_CALLBACK(menu_destroy), objtounref); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, event ? event->time : 0); } static char *str_copy = NULL; /* for all pop-up menus */ void menu_nickmenu(window_t *sess, GdkEventButton *event, char *nick, int num_sel) { char buf[512]; GtkWidget *menu = gtk_menu_new(); struct userlist *user; if (str_copy) free(str_copy); str_copy = strdup(nick); submenu_list = NULL; /* first time through, might not be 0 */ /* [XXX] khem? z czym to sie je? */ /* more than 1 nick selected? */ if (num_sel > 1) { snprintf(buf, sizeof(buf), "Zaznaczyles: %d uzytkownikow.", num_sel); menu_quick_item(0, buf, menu, 0, 0, 0); menu_quick_item(0, 0, menu, XCMENU_SHADED, 0, 0); } else { user = userlist_find(0, nick); #warning "userlist_find() + czlonkowie konferencji" /* XXX, * jesli bedziemy tworzyc support dla konferencji w userliscie. * to tutaj zrob: * if (!user) * user = ......... */ if (user) { const char fmt[] = "%-11s %s"; const char fmtd[] = "%-11s %d"; const char fmtip[] = "%-11s %s:%d"; GtkWidget *submenu = menu_quick_sub(nick, menu, NULL, XCMENU_DOLIST, -1); snprintf(buf, sizeof(buf), fmtd, "Numerek:", user->uin); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); /* XXX, ? */ /* XXX, stworzyc funkcje ktora to bedzie automatyzowac? */ /* XXX, wyswietl: u->status, u->descr */ if (user->nickname && strcmp(user->nickname, nick)) { char *real = g_markup_escape_text(user->nickname, -1); snprintf(buf, sizeof(buf), fmt, "Nick:", real); g_free(real); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } /* XXX, imie i nazwisko razem? */ if (user->first_name) { char *real = g_markup_escape_text(user->first_name, -1); snprintf(buf, sizeof(buf), fmt, "Imie:", real); g_free(real); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } if (user->last_name) { char *real = g_markup_escape_text(user->last_name, -1); snprintf(buf, sizeof(buf), fmt, "Nazwisko:", real); g_free(real); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } if (user->mobile) { char *real = g_markup_escape_text(user->mobile, -1); snprintf(buf, sizeof(buf), fmt, "Telefon:", real); g_free(real); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } if (user->groups) { char *groups = group_to_string(user->groups, 0, 1); if (strcmp(groups, "")) { char *real = g_markup_escape_text(groups, -1); snprintf(buf, sizeof(buf), fmt, "Grupy:", real); g_free(real); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } xfree(groups); } if (user->email) { char *real = g_markup_escape_text(user->email, -1); snprintf(buf, sizeof(buf), fmt, "Email:", real); g_free(real); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } if (user->ip.s_addr) { snprintf(buf, sizeof(buf), fmtip, "IP:", inet_ntoa(user->ip), user->port); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } if (GG_S_NA(user->status)) { if (user->last_seen) { char min[196]; snprintf(min, sizeof(min), "%u minut temu (O %s)", (unsigned int)((time(0) - user->last_seen) / 60), /* %u minut temu */ timestamp_time(format_find("user_info_last_seen_time"), user->last_seen)); /* O %s */ /* Ostatnio widziano: 666 minut temu (O 10:23:34) */ snprintf(buf, sizeof(buf), fmt, "Ostatnio widziano:", min); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); /* XXX, last_descr */ if (user->last_ip.s_addr) { snprintf(buf, sizeof(buf), fmtip, "Ostatnie IP:", inet_ntoa(user->last_ip), user->last_port); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } } else { snprintf(buf, sizeof(buf), fmt, "Ostatnio widziano:", "Nigdy"); menu_quick_item(0, buf, submenu, XCMENU_MARKUP, 0, 0); } } /* u->protocol (?) */ /* u->image_size (?) */ menu_quick_endsub(); menu_quick_item(0, 0, menu, XCMENU_SHADED, 0, 0); } } #if 0 if (num_sel > 1) menu_create(menu, popup_list, NULL, FALSE); else menu_create(menu, popup_list, str_copy, FALSE); #endif #if 0 if (num_sel == 0) /* xtext click */ menu_add_plugin_items(menu, "\x5$NICK", str_copy); else /* userlist treeview click */ menu_add_plugin_items(menu, "\x5$NICK", NULL); #endif menu_popup(menu, event, NULL); } /* stuff for the View menu */ static void menu_showhide_cb(window_t *sess) { if (hidemenu_config) gtk_widget_hide(sess->gui->menu); else gtk_widget_show(sess->gui->menu); } static void menu_topic_showhide_cb(window_t *sess) { if (config_header_size) gtk_widget_show(sess->gui->topic_bar); else gtk_widget_hide(sess->gui->topic_bar); } static void menu_userlist_showhide_cb(window_t *sess) { mg_decide_userlist(sess, TRUE); } #if 0 static void menu_ulbuttons_showhide_cb(session *sess) { if (prefs.userlistbuttons) gtk_widget_show(sess->gui->button_box); else gtk_widget_hide(sess->gui->button_box); } static void menu_cmbuttons_showhide_cb(session *sess) { switch (sess->type) { case SESS_CHANNEL: if (prefs.chanmodebuttons) gtk_widget_show(sess->gui->topicbutton_box); else gtk_widget_hide(sess->gui->topicbutton_box); break; default: gtk_widget_hide(sess->gui->topicbutton_box); } } #endif /* XXX, uzyc ui_gtk_foreach_window_data() ? */ static void menu_setting_foreach(void (*func)(window_t *), int id, guint state) { list_t l; int once = 0; for (l = windows; l; l = l->next) { window_t *w = l->data; if (w->gui->is_tab) { if (!once) once = 1; else continue; } if (id != -1) GTK_CHECK_MENU_ITEM(w->gui->menu_item[id])->active = state; if (func) func(w); } } void menu_bar_toggle(void) { hidemenu_config = !hidemenu_config; menu_setting_foreach(menu_showhide_cb, MENU_ID_MENUBAR, !hidemenu_config); } static void menu_bar_toggle_cb(void) { menu_bar_toggle(); if (hidemenu_config) { /* It's FE_MSG_INFO */ printf("The Menubar is now hidden. You can show it again " "by pressing F9 or right-clicking in a blank part of " "the main text area.\n"); } } static void menu_topicbar_toggle(GtkWidget *wid, gpointer ud) { config_header_size = !config_header_size; menu_setting_foreach(menu_topic_showhide_cb, MENU_ID_TOPICBAR, config_header_size); } static void menu_userlist_toggle(GtkWidget *wid, gpointer ud) { config_contacts = !config_contacts; menu_setting_foreach(menu_userlist_showhide_cb, MENU_ID_USERLIST, config_contacts); } #if 0 static void menu_ulbuttons_toggle(GtkWidget *wid, gpointer ud) { prefs.userlistbuttons = !prefs.userlistbuttons; menu_setting_foreach(menu_ulbuttons_showhide_cb, MENU_ID_ULBUTTONS, prefs.userlistbuttons); } static void menu_cmbuttons_toggle(GtkWidget *wid, gpointer ud) { prefs.chanmodebuttons = !prefs.chanmodebuttons; menu_setting_foreach(menu_cmbuttons_showhide_cb, MENU_ID_MODEBUTTONS, prefs.chanmodebuttons); } void menu_middlemenu(session *sess, GdkEventButton * event) { GtkWidget *menu; GtkAccelGroup *accel_group; accel_group = gtk_accel_group_new(); menu = menu_create_main(accel_group, FALSE, sess->server->is_away, !sess->gui->is_tab, NULL); menu_popup(menu, event, accel_group); } static void open_url_cb(GtkWidget *item, char *url) { char buf[512]; /* pass this to /URL so it can handle irc:// */ snprintf(buf, sizeof(buf), "URL %s", url); handle_command(current_sess, buf, FALSE); } static void copy_to_clipboard_cb(GtkWidget *item, char *url) { gtkutil_copy_to_clipboard(item, NULL, url); } void menu_urlmenu(GdkEventButton * event, char *url) { GtkWidget *menu; char *tmp, *chop; if (str_copy) free(str_copy); str_copy = strdup(url); menu = gtk_menu_new(); /* more than 51 chars? Chop it */ if (g_utf8_strlen(str_copy, -1) >= 52) { tmp = strdup(str_copy); chop = g_utf8_offset_to_pointer(tmp, 48); chop[0] = chop[1] = chop[2] = '.'; chop[3] = 0; menu_quick_item(0, tmp, menu, XCMENU_SHADED, 0, 0); free(tmp); } else { menu_quick_item(0, str_copy, menu, XCMENU_SHADED, 0, 0); } menu_quick_item(0, 0, menu, XCMENU_SHADED, 0, 0); /* Two hardcoded entries */ if (strncmp(str_copy, "irc://", 6) == 0 || strncmp(str_copy, "ircs://", 7) == 0) menu_quick_item_with_callback(open_url_cb, _("Connect"), menu, str_copy); else menu_quick_item_with_callback(open_url_cb, _("Open Link in Browser"), menu, str_copy); menu_quick_item_with_callback(copy_to_clipboard_cb, _("Copy Selected Link"), menu, str_copy); /* custom ones from urlhandlers.conf */ menu_create(menu, urlhandler_list, str_copy, TRUE); menu_add_plugin_items(menu, "\x4$URL", str_copy); menu_popup(menu, event, NULL); } #endif static int serverlist_open() { static GtkWidget *dialog = NULL; int ret; if (dialog) { gtk_window_present(GTK_WINDOW(dialog)); return 0; } if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) ret = 1; else ret = 0; gtk_widget_destroy(dialog); dialog = NULL; return 0; } static void menu_open_server_list(GtkWidget *wid, gpointer none) { printf("menu_open_server_list() stub\n"); return; if ((serverlist_open())) { /* XXX jesli uzytkownik kliknal OK */ } } static void menu_settings(GtkWidget *wid, gpointer none) { #if 0 extern void setup_open(void); setup_open(); #endif printf("menu_settings() stub! :)\n"); } static void menu_about(GtkWidget *wid, gpointer sess) { GtkWidget *vbox, *label, *hbox; static GtkWidget *about = NULL; char buf[512]; if (about) { gtk_window_present(GTK_WINDOW(about)); return; } about = gtk_dialog_new(); gtk_window_set_position(GTK_WINDOW (about), GTK_WIN_POS_CENTER); gtk_window_set_resizable(GTK_WINDOW (about), FALSE); gtk_window_set_title(GTK_WINDOW(about), "O programie..."); vbox = GTK_DIALOG(about)->vbox; wid = gtk_image_new_from_pixbuf(pix_ekg); gtk_container_add(GTK_CONTAINER(vbox), wid); label = gtk_label_new(NULL); gtk_label_set_selectable(GTK_LABEL (label), TRUE); gtk_container_add(GTK_CONTAINER(vbox), label); snprintf(buf, sizeof (buf), "ekg 1.7\n\n" "Eksperymentalny Klient Gadu-Gadu wersja 1.7\n" "Skompilowano: %s\n\n" "gtk frontend based on xchat: \302\251 1998-2007 Peter \305\275elezn\303\275 <zed@xchat.org>", compile_time()); gtk_label_set_markup(GTK_LABEL(label), buf); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); hbox = gtk_hbox_new(0, 2); gtk_container_add(GTK_CONTAINER(vbox), hbox); wid = gtk_button_new_from_stock(GTK_STOCK_CLOSE); GTK_WIDGET_SET_FLAGS(GTK_WIDGET(wid), GTK_CAN_DEFAULT); gtk_dialog_add_action_widget(GTK_DIALOG(about), wid, GTK_RESPONSE_OK); gtk_widget_grab_default(wid); gtk_widget_show_all(about); gtk_dialog_run(GTK_DIALOG(about)); gtk_widget_destroy(about); about = NULL; } #if 0 static void menu_usermenu(void) { editlist_gui_open(NULL, NULL, usermenu_list, _("XChat: User menu"), "usermenu", "usermenu.conf", 0); } static void usermenu_create(GtkWidget *menu) { menu_create(menu, usermenu_list, "", FALSE); menu_quick_item(0, 0, menu, XCMENU_SHADED, 0, 0); /* sep */ menu_quick_item_with_callback(menu_usermenu, _("Edit This Menu..."), menu, 0); } static void usermenu_destroy(GtkWidget *menu) { GList *items = ((GtkMenuShell *) menu)->children; GList *next; while (items) { next = items->next; gtk_widget_destroy(items->data); items = next; } } void usermenu_update(void) { int done_main = FALSE; GSList *list = sess_list; session *sess; GtkWidget *menu; while (list) { sess = list->data; menu = sess->gui->menu_item[MENU_ID_USERMENU]; if (sess->gui->is_tab) { if (!done_main && menu) { usermenu_destroy(menu); usermenu_create(menu); done_main = TRUE; } } else if (menu) { usermenu_destroy(menu); usermenu_create(menu); } list = list->next; } } #endif static void menu_newchannel_window(GtkWidget *wid, gpointer none) { int old = new_window_in_tab_config; new_window_in_tab_config = 0; ui_gtk_window_new(NULL, 0); new_window_in_tab_config = old; } static void menu_newchannel_tab(GtkWidget *wid, gpointer none) { int old = new_window_in_tab_config; new_window_in_tab_config = 1; ui_gtk_window_new(NULL, 0); new_window_in_tab_config = old; } static void menu_detach(GtkWidget *wid, gpointer none) { mg_detach(window_current, 0); } static void menu_close(GtkWidget *wid, gpointer none) { #warning "XXX, czy takie behaviour jest ok." if (window_current->id == 1) mg_open_quit_dialog(FALSE); else ui_gtk_window_kill(window_current, 0); } static void menu_quit(GtkWidget *wid, gpointer none) { mg_open_quit_dialog(FALSE); } #if 0 static void menu_search() { search_open(current_sess); } static void menu_rawlog(GtkWidget *wid, gpointer none) { open_rawlog(current_sess->server); } #endif static void menu_resetmarker(GtkWidget *wid, gpointer none) { gtk_xtext_reset_marker_pos(GTK_XTEXT(window_current->gui->xtext)); } static void menu_flushbuffer(GtkWidget *wid, gpointer none) { ui_gtk_window_clear(window_current); } #if 0 static void savebuffer_req_done(session *sess, char *file) { int fh; if (!file) return; fh = open(file, O_TRUNC | O_WRONLY | O_CREAT, 0600); if (fh != -1) { gtk_xtext_save(GTK_XTEXT(sess->gui->xtext), fh); close(fh); } } static void menu_savebuffer(GtkWidget *wid, gpointer none) { gtkutil_file_req(_("Select an output filename"), savebuffer_req_done, current_sess, NULL, FRF_WRITE); } #endif static void menu_disconnect(GtkWidget *wid, gpointer none) { command_exec(NULL, "/disconnect", 0); } static void menu_reconnect(GtkWidget *wid, gpointer none) { command_exec(NULL, "/reconnect", 0); } #if 0 static void menu_away(GtkCheckMenuItem *item, gpointer none) { handle_command(current_sess, item->active ? "away" : "back", FALSE); } #endif static void menu_conference_cb(GtkWidget *dialog, gint response, GtkEntry *entry) { switch (response) { case GTK_RESPONSE_ACCEPT: printf("menu_conference_cb() RESPONSE_OK: stub! [%s]\n", entry->text ? entry->text : "(null)"); // menu_chan_join(NULL, entry->text); break; case GTK_RESPONSE_HELP: printf("menu_conference_cb() RESPOSNE_HELP STUB!\n"); // chanlist_opengui(current_sess->server, TRUE); break; } gtk_widget_destroy(dialog); // handle_command(current_sess, item->active ? "away" : "back", FALSE); } static void menu_conference_entry_cb(GtkWidget *entry, GtkDialog *dialog) { gtk_dialog_response(dialog, GTK_RESPONSE_ACCEPT); } static void menu_conference(GtkWidget *wid, gpointer none) { GtkWidget *hbox, *dialog, *entry, *label; dialog = gtk_dialog_new_with_buttons("Utworz konferencje", GTK_WINDOW(parent_window), 0, "Wybierz uzytkownikow z listy", GTK_RESPONSE_HELP, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_box_set_homogeneous(GTK_BOX(GTK_DIALOG(dialog)->vbox), TRUE); gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE); hbox = gtk_hbox_new(TRUE, 0); entry = gtk_entry_new(); // GTK_ENTRY(entry)->editable = 0; /* avoid auto-selection */ // gtk_entry_set_text(GTK_ENTRY(entry), "#"); g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(menu_conference_entry_cb), dialog); gtk_box_pack_end(GTK_BOX(hbox), entry, 0, 0, 0); label = gtk_label_new("Wpisz osoby z ktorymi chcesz rozmawiac"); gtk_box_pack_end(GTK_BOX(hbox), label, 0, 0, 0); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(menu_conference_cb), entry); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); gtk_widget_show_all(dialog); // gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); // gtk_editable_set_position(GTK_EDITABLE(entry), 1); } #if 0 static void menu_blocklist(GtkWidget *wid, gpointer none) { banlist_opengui(current_sess); } static void menu_rpopup(void) { editlist_gui_open(_("Text"), _("Replace with"), replace_list, _("XChat: Replace"), "replace", "replace.conf", 0); } static void menu_urlhandlers(void) { editlist_gui_open(NULL, NULL, urlhandler_list, _("XChat: URL Handlers"), "urlhandlers", "urlhandlers.conf", url_help); } static void menu_evtpopup(void) { pevent_dialog_show(); } static void menu_dcc_win(GtkWidget *wid, gpointer none) { fe_dcc_open_recv_win(FALSE); fe_dcc_open_send_win(FALSE); } static void menu_dcc_voice_win(GtkWidget *wid, gpointer none) { fe_dcc_open_chat_win(FALSE); } #endif void menu_change_layout(void) { if (tab_layout_config == 0) { menu_setting_foreach(NULL, MENU_ID_LAYOUT_TABS, 1); menu_setting_foreach(NULL, MENU_ID_LAYOUT_TREE, 0); mg_change_layout(0); } else { menu_setting_foreach(NULL, MENU_ID_LAYOUT_TABS, 0); menu_setting_foreach(NULL, MENU_ID_LAYOUT_TREE, 1); mg_change_layout(2); } } static void menu_layout_cb(GtkWidget *item, gpointer none) { tab_layout_config = 2; if (GTK_CHECK_MENU_ITEM(item)->active) tab_layout_config = 0; menu_change_layout(); } static GdkPixbuf *pix_book = NULL; /* XXX */ /* stubs */ #define menu_docs NULL #define menu_onhandlers NULL /* XXX, Fajnie bedzie miec graficzny konfigurator /on */ #define menu_blocklist NULL #define menu_conferences NULL #define menu_dcc_win NULL #define menu_dcc_voice_win NULL #define ignore_gui_open NULL static struct mymenu mymenu[] = { {"ekg", 0, 0, M_NEWMENU, 0, 0, 1}, { "Wybierz serwer", menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 0, 1, GDK_s}, {0, 0, 0, M_SEP, 0, 0, 0}, { "Nowe okno", 0, GTK_STOCK_NEW, M_MENUSUB, 0, 0, 1}, {"W zakladce", menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1}, {"Osobno", menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, {0, 0, 0, M_SEP, 0, 0, 0}, #ifdef WITH_PYTHON #define menu_loadplugin NULL { "Zaladuj skrypt", menu_loadplugin, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0, 1}, #else { "Zaladuj skrypt", NULL, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0, 0}, /* XXX, powinno byc bardziej szare.. */ #endif {0, 0, 0, M_SEP, 0, 0, 0}, /* 9 */ #define DETACH_OFFSET (10) {0, menu_detach, GTK_STOCK_REDO, M_MENUSTOCK, 0, 0, 1, GDK_I}, /* 10 */ #define CLOSE_OFFSET (11) {0, menu_close, GTK_STOCK_CLOSE, M_MENUSTOCK, 0, 0, 1, GDK_w}, /* 11 */ {0, 0, 0, M_SEP, 0, 0, 0}, {"Wyjdz", menu_quit, GTK_STOCK_QUIT, M_MENUSTOCK, 0, 0, 1, GDK_q}, /* 13 */ {"Widok", 0, 0, M_NEWMENU, 0, 0, 1}, #define MENUBAR_OFFSET (15) {"Menu", menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1, GDK_F9}, {"Headerbar", menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1}, {"Lista kontatkow", menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1, GDK_F7}, #if 0 {N_("U_serlist Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1}, {N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1}, #endif {0, 0, 0, M_SEP, 0, 0, 0}, {"Okna jako:", 0, 0, M_MENUSUB, 0, 0, 1}, /* 20 */ /* XXX, tlumaczenie: "_Channel Switcher" */ #define TABS_OFFSET (20) {"Przyciski", menu_layout_cb, 0, M_MENURADIO, MENU_ID_LAYOUT_TABS, 0, 1}, /* XXX, tlumaczenie: "_Tabs" */ {"Lista", 0, 0, M_MENURADIO, MENU_ID_LAYOUT_TREE, 0, 1}, /* XXX, tlumaczenie: "T_ree" */ {0, 0, 0, M_END, 0, 0, 0}, {"Roznosci", 0, 0, M_NEWMENU, 0, 0, 1}, /* XXX, tlumaczenie: "_Server" */ {"Rozlacz", menu_disconnect, GTK_STOCK_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1}, {"Reconnect", menu_reconnect, GTK_STOCK_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1}, {"Utworz konferencje", menu_conference, GTK_STOCK_JUMP_TO, M_MENUSTOCK, MENU_ID_JOIN, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, #if 0 /* XXX, pomyslec? */ {"Dostepny", menu_avail, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_a}, #define AWAY_OFFSET (38) {"Zajety", menu_away, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_a}, {"Niewidoczny", menu_invisible, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_a}, #endif #if 0 {N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 39 */ #endif {"Ustawienia", 0, 0, M_NEWMENU, 0, 0, 1}, /* S_ettings */ {"Preferencje", menu_settings, GTK_STOCK_PREFERENCES, M_MENUSTOCK, 0, 0, 1}, /* _Preferences */ {"Zaawansowane", 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 0, 1}, /* Advanced */ {"Zdarzenia (/on)", menu_onhandlers, 0, M_MENUITEM, 0, 0, 1}, #if 0 {N_("Auto Replace..."), menu_rpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("Text Events..."), menu_evtpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("URL Handlers..."), menu_urlhandlers, 0, M_MENUITEM, 0, 0, 1}, {N_("Userlist Buttons..."), menu_ulbuttons, 0, M_MENUITEM, 0, 0, 1}, #endif {0, 0, 0, M_END, 0, 0, 0}, /* 52 */ {"Okna", 0, 0, M_NEWMENU, 0, 0, 1}, {"Zablokowani", menu_blocklist, 0, M_MENUITEM, 0, 0, 1}, {"Konferencje", menu_conferences, 0, M_MENUITEM, 0, 0, 1}, {"Polaczenia bezposrednie", menu_dcc_win, 0, M_MENUITEM, 0, 0, 1}, {"Rozmowy glosowe", menu_dcc_voice_win, 0, M_MENUITEM, 0, 0, 1}, {"Ignorowani", ignore_gui_open, 0, M_MENUITEM, 0, 0, 1}, #if 0 {N_("Character Chart..."), ascii_open, 0, M_MENUITEM, 0, 0, 1}, {N_("Notify List..."), notify_opengui, 0, M_MENUITEM, 0, 0, 1}, {N_("Plugins and Scripts..."), menu_pluginlist, 0, M_MENUITEM, 0, 0, 1}, {N_("Raw Log..."), menu_rawlog, 0, M_MENUITEM, 0, 0, 1}, /* 62 */ #endif {0, 0, 0, M_SEP, 0, 0, 0}, {"Resetuj marker", menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_m}, /* Reset Marker Line */ {"Czysc okno", menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 0, 1, GDK_l}, /* C_lear Text */ #if 0 #define SEARCH_OFFSET 67 {N_("Search Text..."), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_f}, {N_("Save Text..."), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 0, 1}, #endif {"Pomoc", 0, 0, M_NEWMENU, 0, 0, 1}, /* 69 */ {"Dokumentacja...", menu_docs, GTK_STOCK_HELP, M_MENUSTOCK, 0, 0, 1, GDK_F1}, {"O ekg..", menu_about, GTK_STOCK_ABOUT, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, }; GtkWidget *create_icon_menu(char *labeltext, void *stock_name, int is_stock) { GtkWidget *item, *img; if (is_stock) img = gtk_image_new_from_stock(stock_name, GTK_ICON_SIZE_MENU); else img = gtk_image_new_from_pixbuf(*((GdkPixbuf **)stock_name)); item = gtk_image_menu_item_new_with_mnemonic(labeltext); gtk_image_menu_item_set_image((GtkImageMenuItem *) item, img); gtk_widget_show(img); return item; } #if GTK_CHECK_VERSION(2,4,0) /* Override the default GTK2.4 handler, which would make menu bindings not work when the menu-bar is hidden. */ static gboolean menu_canacaccel(GtkWidget *widget, guint signal_id, gpointer user_data) { /* GTK2.2 behaviour */ return GTK_WIDGET_IS_SENSITIVE(widget); } #endif #if 0 /* === STUFF FOR /MENU === */ static GtkMenuItem * menu_find_item(GtkWidget *menu, char *name) { GList *items = ((GtkMenuShell *) menu)->children; GtkMenuItem *item; GtkWidget *child; const char *labeltext; while (items) { item = items->data; child = GTK_BIN(item)->child; if (child) { /* separators arn't labels, skip them */ labeltext = g_object_get_data(G_OBJECT(item), "name"); if (!labeltext) labeltext = gtk_label_get_text(GTK_LABEL(child)); if (!menu_streq(labeltext, name, 1)) return item; } else if (name == NULL) { return item; } items = items->next; } return NULL; } static GtkWidget * menu_find_path(GtkWidget *menu, char *path) { GtkMenuItem *item; char *s; char name[128]; int len; /* grab the next part of the path */ s = strchr(path, '/'); len = s - path; if (!s) len = strlen(path); len = MIN(len, sizeof(name) - 1); memcpy(name, path, len); name[len] = 0; item = menu_find_item(menu, name); if (!item) return NULL; menu = gtk_menu_item_get_submenu(item); if (!menu) return NULL; path += len; if (*path == 0) return menu; return menu_find_path(menu, path + 1); } static GtkWidget * menu_find(GtkWidget *menu, char *path, char *label) { GtkWidget *item = NULL; if (path[0] != 0) menu = menu_find_path(menu, path); if (menu) item = (GtkWidget *)menu_find_item(menu, label); return item; } static void menu_foreach_gui(menu_entry * me, void (*callback) (GtkWidget *, menu_entry *, char *)) { GSList *list = sess_list; int tabdone = FALSE; session *sess; if (!me->is_main) return; /* not main menu */ while (list) { sess = list->data; /* do it only once for tab sessions, since they share a GUI */ if (!sess->gui->is_tab || !tabdone) { callback(sess->gui->menu, me, NULL); if (sess->gui->is_tab) tabdone = TRUE; } list = list->next; } } static void menu_update_cb(GtkWidget *menu, menu_entry * me, char *target) { GtkWidget *item; item = menu_find(menu, me->path, me->label); if (item) { gtk_widget_set_sensitive(item, me->enable); /* must do it without triggering the callback */ if (GTK_IS_CHECK_MENU_ITEM(item)) GTK_CHECK_MENU_ITEM(item)->active = me->state; } } /* radio state changed via mouse click */ static void menu_radio_cb(GtkCheckMenuItem * item, menu_entry * me) { me->state = 0; if (item->active) me->state = 1; /* update the state, incase this was changed via right-click. */ /* This will update all other windows and menu bars */ menu_foreach_gui(me, menu_update_cb); if (me->state && me->cmd) handle_command(current_sess, me->cmd, FALSE); } /* toggle state changed via mouse click */ static void menu_toggle_cb(GtkCheckMenuItem * item, menu_entry * me) { me->state = 0; if (item->active) me->state = 1; /* update the state, incase this was changed via right-click. */ /* This will update all other windows and menu bars */ menu_foreach_gui(me, menu_update_cb); if (me->state) handle_command(current_sess, me->cmd, FALSE); else handle_command(current_sess, me->ucmd, FALSE); } static GtkWidget * menu_radio_item(char *label, GtkWidget *menu, void *callback, void *userdata, int state, char *groupname) { GtkWidget *item; GtkMenuItem *parent; GSList *grouplist = NULL; parent = menu_find_item(menu, groupname); if (parent) grouplist = gtk_radio_menu_item_get_group((GtkRadioMenuItem *) parent); item = gtk_radio_menu_item_new_with_label(grouplist, label); gtk_check_menu_item_set_active((GtkCheckMenuItem *) item, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(callback), userdata); gtk_widget_show(item); return item; } static void menu_reorder(GtkMenu * menu, GtkWidget *item, int pos) { if (pos == 0xffff) /* outbound.c uses this default */ return; if (pos < 0) /* position offset from end/bottom */ gtk_menu_reorder_child(menu, item, (g_list_length(GTK_MENU_SHELL(menu)->children) + pos) - 1); else gtk_menu_reorder_child(menu, item, pos); } static GtkWidget *menu_add_radio(GtkWidget *menu, menu_entry * me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path(menu, path); if (menu) { item = menu_radio_item(me->label, menu, menu_radio_cb, me, me->state, me->group); menu_reorder(GTK_MENU(menu), item, me->pos); } return item; } static GtkWidget *menu_add_toggle(GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path(menu, path); if (menu) { item = menu_toggle_item(me->label, menu, menu_toggle_cb, me, me->state); menu_reorder(GTK_MENU(menu), item, me->pos); } return item; } static GtkWidget *menu_add_item(GtkWidget *menu, menu_entry * me, char *target) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path(menu, path); if (menu) { item = menu_quick_item(me->cmd, me->label, menu, me-> markup ? XCMENU_MARKUP | XCMENU_MNEMONIC : XCMENU_MNEMONIC, target, me->icon); menu_reorder(GTK_MENU(menu), item, me->pos); } return item; } static GtkWidget *menu_add_sub(GtkWidget *menu, menu_entry * me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; int pos; if (path[0] != 0) menu = menu_find_path(menu, path); if (menu) { pos = me->pos; if (pos < 0) /* position offset from end/bottom */ pos = g_list_length(GTK_MENU_SHELL(menu)->children) + pos; menu_quick_sub(me->label, menu, &item, me->markup ? XCMENU_MARKUP | XCMENU_MNEMONIC : XCMENU_MNEMONIC, pos); } return item; } static void menu_del_cb(GtkWidget *menu, menu_entry * me, char *target) { GtkWidget *item = menu_find(menu, me->path + me->root_offset, me->label); if (item) gtk_widget_destroy(item); } static void menu_add_cb(GtkWidget *menu, menu_entry * me, char *target) { GtkWidget *item; GtkAccelGroup *accel_group; if (me->group) /* have a group name? Must be a radio item */ item = menu_add_radio(menu, me); else if (me->ucmd) /* have unselect-cmd? Must be a toggle item */ item = menu_add_toggle(menu, me); else if (me->cmd || !me->label) /* label=NULL for separators */ item = menu_add_item(menu, me, target); else item = menu_add_sub(menu, me); if (item) { gtk_widget_set_sensitive(item, me->enable); if (me->key) { accel_group = g_object_get_data(G_OBJECT(menu), "accel"); if (accel_group) /* popup menus don't have them */ gtk_widget_add_accelerator(item, "activate", accel_group, me->key, me->modifier, GTK_ACCEL_VISIBLE); } } } char *fe_menu_add(menu_entry * me) { char *text; menu_foreach_gui(me, menu_add_cb); if (!me->markup) return NULL; if (!pango_parse_markup(me->label, -1, 0, NULL, &text, NULL, NULL)) return NULL; /* return the label with markup stripped */ return text; } void fe_menu_del(menu_entry * me) { menu_foreach_gui(me, menu_del_cb); } void fe_menu_update(menu_entry * me) { menu_foreach_gui(me, menu_update_cb); } #endif /* used to add custom menus to the right-click menu */ static void menu_add_plugin_mainmenu_items(GtkWidget *menu) { #if 0 GSList *list; menu_entry *me; list = menu_list; /* outbound.c */ while (list) { me = list->data; if (me->is_main) menu_add_cb(menu, me, NULL); list = list->next; } #endif } void menu_add_plugin_items(GtkWidget *menu, char *root, char *target) { #if 0 GSList *list; menu_entry *me; list = menu_list; /* outbound.c */ while (list) { me = list->data; if (!me->is_main && !strncmp(me->path, root + 1, root[0])) menu_add_cb(menu, me, target); list = list->next; } #endif } /* === END STUFF FOR /MENU === */ GtkWidget *menu_create_main(void *accel_group, int bar, int away, int toplevel, GtkWidget **menu_widgets) { int i = 0; GtkWidget *item; GtkWidget *menu = NULL; GtkWidget *menu_item = NULL; GtkWidget *menu_bar; GtkWidget *usermenu = NULL; GtkWidget *submenu = NULL; int close_mask = GDK_CONTROL_MASK; GtkSettings *settings; GSList *group = NULL; if (bar) menu_bar = gtk_menu_bar_new(); else menu_bar = gtk_menu_new(); /* /MENU needs to know this later */ g_object_set_data(G_OBJECT(menu_bar), "accel", accel_group); #if GTK_CHECK_VERSION(2,4,0) g_signal_connect(G_OBJECT(menu_bar), "can-activate-accel", G_CALLBACK(menu_canacaccel), 0); #endif /* set the initial state of toggles */ mymenu[MENUBAR_OFFSET].state = !hidemenu_config; mymenu[MENUBAR_OFFSET + 1].state = (config_header_size != 0); mymenu[MENUBAR_OFFSET + 2].state = (config_contacts != 0); #if 0 mymenu[MENUBAR_OFFSET + 3].state = prefs.userlistbuttons; mymenu[MENUBAR_OFFSET + 4].state = prefs.chanmodebuttons; mymenu[AWAY_OFFSET].state = away; #endif switch (tab_layout_config) { case 0: mymenu[TABS_OFFSET].state = 1; mymenu[TABS_OFFSET + 1].state = 0; break; default: mymenu[TABS_OFFSET].state = 0; mymenu[TABS_OFFSET + 1].state = 1; } #if 0 /* change Close binding to ctrl-shift-w when using emacs keys */ settings = gtk_widget_get_settings(menu_bar); if (settings) { char *key_theme = NULL; g_object_get(settings, "gtk-key-theme-name", &key_theme, NULL); if (key_theme) { if (!strcasecmp(key_theme, "Emacs")) { close_mask = GDK_SHIFT_MASK | GDK_CONTROL_MASK; mymenu[SEARCH_OFFSET].key = 0; } g_free(key_theme); } } #endif if (!toplevel) { mymenu[DETACH_OFFSET].text = "Odklej zakladke"; /* _Detach Tab" */ mymenu[CLOSE_OFFSET].text = "Zamknij zakladke"; /* "_Close Tab" */ } else { mymenu[DETACH_OFFSET].text = "Dolacz okno"; /* "_Attach Window" */ mymenu[CLOSE_OFFSET].text = "Zamknij okno"; /* "_Close Window" */ } while (1) { item = NULL; #if 0 if (mymenu[i].id == MENU_ID_USERMENU && !prefs.gui_usermenu) { i++; continue; } #endif switch (mymenu[i].type) { case M_NEWMENU: if (menu) gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu); item = menu = gtk_menu_new(); #if 0 if (mymenu[i].id == MENU_ID_USERMENU) usermenu = menu; #endif menu_item = gtk_menu_item_new_with_mnemonic(mymenu[i].text); /* record the English name for /menu */ g_object_set_data(G_OBJECT(menu_item), "name", mymenu[i].text); gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_item); gtk_widget_show(menu_item); break; case M_MENUPIX: item = create_icon_menu(mymenu[i].text, mymenu[i].image, FALSE); goto normalitem; case M_MENUSTOCK: item = create_icon_menu(mymenu[i].text, mymenu[i].image, TRUE); goto normalitem; case M_MENUITEM: item = gtk_menu_item_new_with_mnemonic(mymenu[i].text); normalitem: if (mymenu[i].key != 0) gtk_widget_add_accelerator(item, "activate", accel_group, mymenu[i].key, mymenu[i].key == GDK_F1 ? 0 : mymenu[i].key == GDK_w ? close_mask : GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); if (mymenu[i].callback) g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(mymenu[i].callback), 0); if (submenu) gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item); else gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); break; case M_MENUTOG: item = gtk_check_menu_item_new_with_mnemonic(mymenu[i].text); togitem: /* must avoid callback for Radio buttons */ GTK_CHECK_MENU_ITEM(item)->active = mymenu[i].state; /*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state); */ if (mymenu[i].key != 0) { gtk_widget_add_accelerator(item, "activate", accel_group, mymenu[i].key, mymenu[i].id == MENU_ID_AWAY ? GDK_MOD1_MASK : GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); } if (mymenu[i].callback) g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(mymenu[i].callback), 0); if (submenu) gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item); else gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); gtk_widget_set_sensitive(item, mymenu[i].sensitive); break; case M_MENURADIO: item = gtk_radio_menu_item_new_with_mnemonic(group, mymenu[i].text); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)); goto togitem; case M_SEP: item = gtk_menu_item_new(); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); break; case M_MENUSUB: group = NULL; submenu = gtk_menu_new(); item = create_icon_menu(mymenu[i].text, mymenu[i].image, TRUE); /* record the English name for /menu */ g_object_set_data(G_OBJECT(item), "name", mymenu[i].text); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); break; /*case M_END: */ default: if (!submenu) { if (menu) { gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu); menu_add_plugin_mainmenu_items(menu_bar); } #if 0 if (usermenu) usermenu_create(usermenu); #endif return (menu_bar); } submenu = NULL; } /* record this GtkWidget * so it's state might be changed later */ if (mymenu[i].id != 0 && menu_widgets) /* this ends up in sess->gui->menu_item[MENU_ID_XXX] */ menu_widgets[mymenu[i].id] = item; i++; } } /********************************************* USERLISTGUI ****************************/ static int ustatus_strip_descr(int status); /* forward */ static gint userlist_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata) { int a1, b1; /* stored in tree */ int a2, b2; /* after ustatus_strip_descr() */ /* XXX, save in tree a2, b2? */ int a3, b3; /* what we've got in contacts_order */ gint sortcol = GPOINTER_TO_INT(userdata); if (sortcol != USERLIST_STATUS) { printf("userlist_sort_func() IE\n"); return 0; } gtk_tree_model_get(model, a, USERLIST_STATUS, &a1, -1); gtk_tree_model_get(model, b, USERLIST_STATUS, &b1, -1); a2 = ustatus_strip_descr(a1); b2 = ustatus_strip_descr(b1); a3 = contacts_order[a2]; b3 = contacts_order[b2]; return (a3 - b3); } void fe_userlist_numbers(window_t *sess) { if (sess == window_current || !gtk_private_ui(sess)->is_tab) { #if 0 char tbuf[256]; if (sess->total) { snprintf(tbuf, sizeof(tbuf), _("%d ops, %d total"), sess->ops, sess->total); tbuf[sizeof(tbuf) - 1] = 0; gtk_label_set_text(GTK_LABEL(sess->gui->namelistinfo), tbuf); } else { gtk_label_set_text(GTK_LABEL(sess->gui->namelistinfo), NULL); } if (sess->type == SESS_CHANNEL && prefs.gui_tweaks & 1) fe_set_title(sess); #endif gtk_label_set_text(GTK_LABEL(gtk_private_ui(sess)->namelistinfo), "%d avail %d not avail...."); } } char **userlist_selection_list(GtkWidget *widget, int *num_ret) { GtkTreeIter iter; GtkTreeView *treeview = (GtkTreeView *) widget; GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); GtkTreeModel *model = gtk_tree_view_get_model(treeview); int i, num_sel; char **nicks; *num_ret = 0; /* first, count the number of selections */ num_sel = 0; if (gtk_tree_model_get_iter_first(model, &iter)) { do { if (gtk_tree_selection_iter_is_selected(selection, &iter)) num_sel++; } while (gtk_tree_model_iter_next(model, &iter)); } if (num_sel < 1) return NULL; nicks = xmalloc(sizeof(char *) * (num_sel + 1)); i = 0; gtk_tree_model_get_iter_first(model, &iter); do { if (gtk_tree_selection_iter_is_selected(selection, &iter)) { gtk_tree_model_get(model, &iter, USERLIST_NICKNAME, &nicks[i], -1); i++; nicks[i] = NULL; } } while (gtk_tree_model_iter_next(model, &iter)); *num_ret = i; return nicks; } static GtkTreeIter *find_row(GtkTreeView *treeview, GtkTreeModel *model, struct userlist *user, int *selected) { static GtkTreeIter iter; struct userlist *row_user; *selected = FALSE; if (gtk_tree_model_get_iter_first(model, &iter)) { do { gtk_tree_model_get(model, &iter, USERLIST_USER, &row_user, -1); if (row_user == user) { if (gtk_tree_view_get_model(treeview) == model) { if (gtk_tree_selection_iter_is_selected (gtk_tree_view_get_selection(treeview), &iter)) *selected = TRUE; } return &iter; } } while (gtk_tree_model_iter_next(model, &iter)); } return NULL; } void userlist_set_value(GtkWidget *treeview, gfloat val) { gtk_adjustment_set_value(gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(treeview)), val); } gfloat userlist_get_value(GtkWidget *treeview) { return gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(treeview))->value; } int fe_userlist_remove(window_t *sess, struct userlist *user) { GtkTreeIter *iter; /* GtkAdjustment *adj; gfloat val, end;*/ int sel; iter = find_row(GTK_TREE_VIEW(sess->gui->user_tree), sess->user_model, user, &sel); if (!iter) return 0; /* adj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (sess->gui->user_tree)); val = adj->value;*/ gtk_list_store_remove(sess->user_model, iter); /* is it the front-most tab? */ /* if (gtk_tree_view_get_model (GTK_TREE_VIEW (sess->gui->user_tree)) == sess->res->user_model) { end = adj->upper - adj->lower - adj->page_size; if (val > end) val = end; gtk_adjustment_set_value (adj, val); }*/ return sel; } static int ustatus_strip_descr(int status) { switch (status) { case GG_STATUS_AVAIL: case GG_STATUS_AVAIL_DESCR: return PIXBUF_AVAIL; case GG_STATUS_BUSY: case GG_STATUS_BUSY_DESCR: return PIXBUF_AWAY; case GG_STATUS_NOT_AVAIL: case GG_STATUS_NOT_AVAIL_DESCR: return PIXBUF_NOTAVAIL; case GG_STATUS_INVISIBLE: case GG_STATUS_INVISIBLE_DESCR: return PIXBUF_INVISIBLE; case GG_STATUS_BLOCKED: return PIXBUF_BLOCKED; } printf("ustatus_strip_descr() unk: %d\n", status); return PIXBUF_NOTAVAIL; } gboolean fe_userlist_rehash(window_t *sess, struct userlist *u) { GtkTreeIter *iter; int sel; int do_away = TRUE; if (!(iter = find_row(GTK_TREE_VIEW(sess->gui->user_tree), sess->user_model, u, &sel))) return 0; #if 0 if (prefs.away_size_max < 1 || !prefs.away_track) do_away = FALSE; #endif gtk_list_store_set(GTK_LIST_STORE(sess->user_model), iter, USERLIST_STATUS, u->status, USERLIST_NICKNAME, u->display, USERLIST_UIN, u->uin, USERLIST_DESCRIPTION, u->descr, // USERLIST_COLOR, /* (do_away) */ FALSE, ? (newuser->away ? &colors[COL_AWAY] : NULL) : */ (NULL), -1); return 0; } void fe_userlist_insert(window_t *sess, struct userlist *u) { GtkTreeModel *model = gtk_private(sess)->user_model; GtkTreeIter iter; int do_away = TRUE; #if 0 if (prefs.away_size_max < 1 || !prefs.away_track) do_away = FALSE; #endif gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter, -1, USERLIST_STATUS, u->status, USERLIST_NICKNAME, u->display, USERLIST_UIN, u->uin, USERLIST_DESCRIPTION, u->descr, USERLIST_USER, u, // USERLIST_COLOR, /* (do_away) */ FALSE, ? (newuser->away ? &colors[COL_AWAY] : NULL) : */ (NULL), -1); #if DARK /* is it me? */ if (newuser->me && sess->gui->nick_box) { if (!sess->gui->is_tab || sess == current_tab) mg_set_access_icon(sess->gui, pix, sess->server->is_away); } #if 0 /* not mine IF !! */ if (prefs.hilitenotify && notify_isnotify(sess, newuser->nick)) { gtk_clist_set_foreground((GtkCList *) sess->gui->user_clist, row, &colors[prefs.nu_color]); } #endif #endif } void fe_userlist_clear(window_t *sess) { gtk_list_store_clear(gtk_private(sess)->user_model); } void *userlist_create_model(void) { GtkTreeSortable *sortable; void *liststore; liststore = gtk_list_store_new(USERLIST_COLS, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR); sortable = GTK_TREE_SORTABLE(liststore); gtk_tree_sortable_set_sort_func(sortable, USERLIST_STATUS, userlist_sort_func, GINT_TO_POINTER(USERLIST_STATUS), NULL); /* initial sort */ gtk_tree_sortable_set_sort_column_id(sortable, USERLIST_STATUS, GTK_SORT_ASCENDING); return liststore; } static void userlist_render_pixmap(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { int status; gtk_tree_model_get(tree_model, iter, GPOINTER_TO_INT(data), &status, -1); g_object_set(cell, "pixbuf", gg_pixs[ustatus_strip_descr(status)], NULL); } static void userlist_add_columns(GtkTreeView * treeview) { GtkCellRenderer *renderer; /* icon column */ renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_insert_column_with_data_func(GTK_TREE_VIEW(treeview), -1, NULL, renderer, userlist_render_pixmap, (gpointer) USERLIST_STATUS, NULL); /* nick column */ renderer = gtk_cell_renderer_text_new(); gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, NULL, renderer, "text", USERLIST_NICKNAME, "foreground-gdk", USERLIST_COLOR, NULL); /* description column (?) */ if (show_descr_in_userlist_config) { renderer = gtk_cell_renderer_text_new(); gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, NULL, renderer, "text", USERLIST_DESCRIPTION, NULL); } } static gint userlist_click_cb(GtkWidget *widget, GdkEventButton * event, gpointer userdata) { char **nicks; int i; GtkTreeSelection *sel; GtkTreePath *path; if (!event) return FALSE; if (!(event->state & GDK_CONTROL_MASK) && event->type == GDK_2BUTTON_PRESS /* && prefs.doubleclickuser[0] */) { nicks = userlist_selection_list(widget, &i); if (nicks) { /* nick_command_parse(current_sess, prefs.doubleclickuser, nicks[0], nicks[0]); */ command_exec_format(window_current->target, 0, ("/query %s"), nicks[0]); while (i) { i--; g_free(nicks[i]); } free(nicks); } return TRUE; } if (event->button == 3) { /* do we have a multi-selection? */ nicks = userlist_selection_list(widget, &i); if (nicks && i > 1) { menu_nickmenu(window_current, event, nicks[0], i); while (i) { i--; g_free(nicks[i]); } free(nicks); return TRUE; } if (nicks) { g_free(nicks[0]); free(nicks); } sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), event->x, event->y, &path, 0, 0, 0)) { gtk_tree_selection_unselect_all(sel); gtk_tree_selection_select_path(sel, path); gtk_tree_path_free(path); nicks = userlist_selection_list(widget, &i); if (nicks) { menu_nickmenu(window_current, event, nicks[0], i); while (i) { i--; g_free(nicks[i]); } free(nicks); } } else { gtk_tree_selection_unselect_all(sel); } return TRUE; } return FALSE; } static gboolean userlist_key_cb(GtkWidget *wid, GdkEventKey * evt, gpointer userdata) { #if 0 if (evt->keyval >= GDK_asterisk && evt->keyval <= GDK_z) { /* dirty trick to avoid auto-selection */ SPELL_ENTRY_SET_EDITABLE(current_sess->gui->input_box, FALSE); gtk_widget_grab_focus(current_sess->gui->input_box); SPELL_ENTRY_SET_EDITABLE(current_sess->gui->input_box, TRUE); gtk_widget_event(current_sess->gui->input_box, (GdkEvent *) evt); return TRUE; } #endif return FALSE; } GtkWidget *userlist_create(GtkWidget *box) { GtkWidget *sw, *treeview; sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), show_descr_in_userlist_config ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(box), sw, TRUE, TRUE, 0); gtk_widget_show(sw); treeview = gtk_tree_view_new(); gtk_widget_set_name(treeview, "xchat-userlist"); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); gtk_tree_selection_set_mode(gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview)), GTK_SELECTION_MULTIPLE); g_signal_connect(G_OBJECT(treeview), "button_press_event", G_CALLBACK(userlist_click_cb), 0); g_signal_connect(G_OBJECT(treeview), "key_press_event", G_CALLBACK(userlist_key_cb), 0); #warning "xchat->ekg2: drag & drop" userlist_add_columns(GTK_TREE_VIEW(treeview)); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); return treeview; } void userlist_show(window_t *sess) { gtk_tree_view_set_model(GTK_TREE_VIEW(gtk_private_ui(sess)->user_tree), gtk_private(sess)->user_model); } /********************************************* GTKUTIL ********************************/ void add_tip(GtkWidget *wid, char *text) { static GtkTooltips *tip = NULL; if (!tip) tip = gtk_tooltips_new(); gtk_tooltips_set_tip(tip, wid, text, 0); } void gtkutil_set_icon(GtkWidget *win) { gtk_window_set_icon(GTK_WINDOW(win), pix_ekg); } GtkWidget *gtkutil_button(GtkWidget *box, char *stock, char *tip, void *callback, void *userdata, char *labeltext) { GtkWidget *wid, *img, *bbox; wid = gtk_button_new(); if (labeltext) { gtk_button_set_label(GTK_BUTTON(wid), labeltext); gtk_button_set_image(GTK_BUTTON(wid), gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU)); if (box) gtk_container_add(GTK_CONTAINER(box), wid); } else { bbox = gtk_hbox_new(0, 0); gtk_container_add(GTK_CONTAINER(wid), bbox); gtk_widget_show(bbox); img = gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU); if (stock == GTK_STOCK_GOTO_LAST) gtk_widget_set_usize(img, 10, 6); gtk_container_add(GTK_CONTAINER(bbox), img); gtk_widget_show(img); gtk_box_pack_start(GTK_BOX(box), wid, 0, 0, 0); } g_signal_connect(G_OBJECT(wid), "clicked", G_CALLBACK(callback), userdata); gtk_widget_show(wid); if (tip) add_tip(wid, tip); return wid; } GtkWidget *gtkutil_window_new(char *title, char *role, int width, int height, int flags) { GtkWidget *win; win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtkutil_set_icon(win); gtk_window_set_title(GTK_WINDOW(win), title); gtk_window_set_default_size(GTK_WINDOW(win), width, height); gtk_window_set_role(GTK_WINDOW(win), role); if (flags & 1) gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_MOUSE); if ((flags & 2) && parent_window) { gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(parent_window)); } return win; } char *gtk_window_target(window_t *window) { if (!window) return ""; if (window->target) return window->target; else if (window->id == 1) return "__status"; else if (window->id == 0) return "__debug"; else return ""; } static PangoAttrList *mg_attr_list_create(GdkColor *col, int size) { PangoAttribute *attr; PangoAttrList *list; list = pango_attr_list_new(); if (col) { attr = pango_attr_foreground_new(col->red, col->green, col->blue); attr->start_index = 0; attr->end_index = 0xffff; pango_attr_list_insert(list, attr); } if (size > 0) { attr = pango_attr_scale_new(size == 1 ? PANGO_SCALE_SMALL : PANGO_SCALE_X_SMALL); attr->start_index = 0; attr->end_index = 0xffff; pango_attr_list_insert(list, attr); } return list; } static void mg_create_tab_colors(void) { if (plain_list) { pango_attr_list_unref(plain_list); pango_attr_list_unref(newmsg_list); pango_attr_list_unref(newdata_list); pango_attr_list_unref(nickseen_list); pango_attr_list_unref(away_list); } plain_list = mg_attr_list_create(NULL, tab_small_config); newdata_list = mg_attr_list_create(&colors[COL_NEW_DATA], tab_small_config); nickseen_list = mg_attr_list_create(&colors[COL_HILIGHT], tab_small_config); newmsg_list = mg_attr_list_create(&colors[COL_NEW_MSG], tab_small_config); away_list = mg_attr_list_create(&colors[COL_AWAY], FALSE); } #ifdef USE_XLIB #include static void set_window_urgency(GtkWidget *win, gboolean set) { XWMHints *hints; hints = XGetWMHints(GDK_WINDOW_XDISPLAY(win->window), GDK_WINDOW_XWINDOW(win->window)); if (set) hints->flags |= XUrgencyHint; else hints->flags &= ~XUrgencyHint; XSetWMHints(GDK_WINDOW_XDISPLAY(win->window), GDK_WINDOW_XWINDOW(win->window), hints); XFree(hints); } static void flash_window(GtkWidget *win) { set_window_urgency(win, TRUE); } static void unflash_window(GtkWidget *win) { set_window_urgency(win, FALSE); } #endif int fe_gui_info(window_t *sess, int info_type) { /* code from fe-gtk.c */ switch (info_type) { case 0: /* window status */ if (!GTK_WIDGET_VISIBLE(GTK_WINDOW(gtk_private_ui(sess)->window))) return 2; /* hidden (iconified or systray) */ #if GTK_CHECK_VERSION(2,4,0) if (gtk_window_is_active(GTK_WINDOW(gtk_private_ui(sess)->window))) #else #if GTK_CHECK_VERSION(2,2,0) if (GTK_WINDOW(gtk_private_ui(sess)->window)->is_active) #endif #endif return 1; /* active/focused */ return 0; /* normal (no keyboard focus or behind a window) */ } return -1; } /* flash the taskbar button */ void fe_flash_window(window_t *sess) { #if defined(WIN32) || defined(USE_XLIB) if (fe_gui_info(sess, 0) != 1) /* only do it if not focused */ flash_window(gtk_private_ui(sess)->window); #endif } /* set a tab plain, red, light-red, or blue */ void fe_set_tab_color(window_t *sess, int col) { if (!gtk_private_ui(sess)->is_tab) return; // col value, what todo values comment. // 0: chan_set_color(sess->tab, plain_list); [new_data = NULL, msg_said = NULL, nick_said = NULL] /* no particular color (theme default) */ // 1: chan_set_color(sess->tab, newdata_list); [new_data = TRUE, msg_said = NULL, nick_said = NULL] /* new data has been displayed (dark red) */ // 2: chan_set_color(sess->tab, newmsg_list); [new_data = NULL, msg_said = TRUE, nick_said = NULL] /* new message arrived in channel (light red) */ // 3: chan_set_color(sess->tab, nickseen_list) ; [new_data = NULL, msg_said = NULL, nick_said = TRUE] /* your nick has been seen (blue) */ if (col == 0) chan_set_color(gtk_private(sess)->tab, plain_list); if (col == 1) chan_set_color(gtk_private(sess)->tab, newdata_list); if (col == 2) chan_set_color(gtk_private(sess)->tab, newmsg_list); } #if 0 static void mg_set_myself_away(gtk_window_ui_t *gui, gboolean away) { gtk_label_set_attributes(GTK_LABEL(GTK_BIN(gui->nick_label)->child), away ? away_list : NULL); } /* change the little icon to the left of your nickname */ void mg_set_access_icon(gtk_window_ui_t *gui, GdkPixbuf *pix, gboolean away) { if (gui->op_xpm) { gtk_widget_destroy(gui->op_xpm); gui->op_xpm = 0; } if (pix) { gui->op_xpm = gtk_image_new_from_pixbuf(pix); gtk_box_pack_start(GTK_BOX(gui->nick_box), gui->op_xpm, 0, 0, 0); gtk_widget_show(gui->op_xpm); } mg_set_myself_away(gui, away); } #endif static gboolean mg_inputbox_focus(GtkWidget *widget, GdkEventFocus *event, gtk_window_ui_t *gui) { list_t l; if (gui->is_tab) return FALSE; for (l = windows; l; l = l->next) { window_t *w = l->data; if (gtk_private(w)->gui == gui) { ui_gtk_window_switch(w->id); return FALSE; } } printf("mg_inputbox_focus() internal error!\n"); return FALSE; } void mg_inputbox_cb(GtkWidget *igad, gtk_window_ui_t *gui) { static int ignore = FALSE; window_t *sess = NULL; char *cmd; if (ignore) return; cmd = GTK_ENTRY(igad)->text; if (cmd[0] == '\0') return; cmd = xstrdup(cmd); /* avoid recursive loop */ ignore = TRUE; gtk_entry_set_text(GTK_ENTRY(igad), ""); ignore = FALSE; /* where did this event come from? */ if (gui->is_tab) { sess = window_current; } else { list_t l; for (l = windows; l; l = l->next) { window_t *w = l->data; if (gtk_private_ui(w) == gui) { sess = w; break; } } if (!sess) printf("FATAL, not found.\n"); } if (sess) { history[0] = cmd; xfree(history[HISTORY_MAX - 1]); memmove(&history[1], &history[0], sizeof(history) - sizeof(history[0])); history_index = 0; history[0] = NULL; cmd = utf8_to_iso(xstrdup(cmd)); command_exec(sess->target, cmd, 0); xfree(cmd); return; } xfree(cmd); } void fe_set_title(window_t *sess) { gtk_window_ui_t *n = gtk_private_ui(sess); if (n->is_tab && sess != window_current) return; gtk_window_set_title(GTK_WINDOW(n->window), "ekg"); } static gboolean mg_windowstate_cb(GtkWindow * wid, GdkEventWindowState * event, gpointer userdata) { #if 0 prefs.gui_win_state = 0; if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) prefs.gui_win_state = 1; if ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && (prefs.gui_tray_flags & 4)) { tray_toggle_visibility(TRUE); gtk_window_deiconify(wid); } #endif return FALSE; } static gboolean mg_configure_cb(GtkWidget *wid, GdkEventConfigure * event, window_t *sess) { #if 0 if (sess == NULL) { /* for the main_window */ if (mg_gui) { if (prefs.mainwindow_save) { sess = current_sess; gtk_window_get_position(GTK_WINDOW(wid), &prefs.mainwindow_left, &prefs.mainwindow_top); gtk_window_get_size(GTK_WINDOW(wid), &prefs.mainwindow_width, &prefs.mainwindow_height); } } } if (sess) { if (sess->type == SESS_DIALOG && prefs.mainwindow_save) { gtk_window_get_position(GTK_WINDOW(wid), &prefs.dialog_left, &prefs.dialog_top); gtk_window_get_size(GTK_WINDOW(wid), &prefs.dialog_width, &prefs.dialog_height); } if (((GtkXText *) sess->gui->xtext)->transparent) gtk_widget_queue_draw(sess->gui->xtext); } #endif return FALSE; } #if 0 /* move to a non-irc tab */ static void mg_show_generic_tab(GtkWidget *box) { int num; GtkWidget *f = NULL; if (current_sess && GTK_WIDGET_HAS_FOCUS(current_sess->gui->input_box)) f = current_sess->gui->input_box; num = gtk_notebook_page_num(GTK_NOTEBOOK(mg_gui->note_book), box); gtk_notebook_set_current_page(GTK_NOTEBOOK(mg_gui->note_book), num); gtk_tree_view_set_model(GTK_TREE_VIEW(mg_gui->user_tree), NULL); gtk_window_set_title(GTK_WINDOW(mg_gui->window), g_object_get_data(G_OBJECT(box), "title")); gtk_widget_set_sensitive(mg_gui->menu, FALSE); if (f) gtk_widget_grab_focus(f); } #endif /* a channel has been focused */ static void mg_focus(window_t *sess) { #if 0 if (sess->gui->is_tab) current_tab = sess; current_sess = sess; /* dirty trick to avoid auto-selection */ SPELL_ENTRY_SET_EDITABLE(sess->gui->input_box, FALSE); gtk_widget_grab_focus(sess->gui->input_box); SPELL_ENTRY_SET_EDITABLE(sess->gui->input_box, TRUE); sess->server->front_session = sess; if (sess->server->server_session != NULL) { if (sess->server->server_session->type != SESS_SERVER) sess->server->server_session = sess; } else { sess->server->server_session = sess; } if (sess->new_data || sess->nick_said || sess->msg_said) { sess->nick_said = FALSE; sess->msg_said = FALSE; sess->new_data = FALSE; /* when called via mg_changui_new, is_tab might be true, but sess->res->tab is still NULL. */ if (sess->res->tab) fe_set_tab_color(sess, 0); } #endif } void mg_set_topic_tip(window_t *sess) { #if 0 char *text; switch (sess->type) { case SESS_CHANNEL: if (sess->topic) { text = g_strdup_printf(_("Topic for %s is: %s"), sess->channel, sess->topic); add_tip(sess->gui->topic_entry, text); g_free(text); } else add_tip(sess->gui->topic_entry, _("No topic is set")); break; default: if (GTK_ENTRY(sess->gui->topic_entry)->text && GTK_ENTRY(sess->gui->topic_entry)->text[0]) add_tip(sess->gui->topic_entry, GTK_ENTRY(sess->gui->topic_entry)->text); else add_tip(sess->gui->topic_entry, NULL); } #endif } static void mg_hide_empty_pane(GtkPaned * pane) { if ((pane->child1 == NULL || !GTK_WIDGET_VISIBLE(pane->child1)) && (pane->child2 == NULL || !GTK_WIDGET_VISIBLE(pane->child2))) { gtk_widget_hide(GTK_WIDGET(pane)); return; } gtk_widget_show(GTK_WIDGET(pane)); } static void mg_hide_empty_boxes(gtk_window_ui_t *gui) { /* hide empty vpanes - so the handle is not shown */ mg_hide_empty_pane((GtkPaned *) gui->vpane_right); mg_hide_empty_pane((GtkPaned *) gui->vpane_left); } static void mg_userlist_showhide(window_t *sess, int show) { gtk_window_ui_t *gui = gtk_private_ui(sess); int handle_size; if (show) { gtk_widget_show(gui->user_box); gui->ul_hidden = 0; gtk_widget_style_get(GTK_WIDGET(gui->hpane_right), "handle-size", &handle_size, NULL); gtk_paned_set_position(GTK_PANED(gui->hpane_right), GTK_WIDGET(gui->hpane_right)->allocation.width - (gui_pane_right_size_config + handle_size)); } else { gtk_widget_hide(gui->user_box); gui->ul_hidden = 1; } mg_hide_empty_boxes(gui); } /* decide if the userlist should be shown or hidden for this tab */ void mg_decide_userlist(window_t *sess, gboolean switch_to_current) { /* when called from menu.c we need this */ if (gtk_private_ui(sess) == mg_gui && switch_to_current) sess = window_current; if (!config_contacts) { mg_userlist_showhide(sess, FALSE); return; } /* xchat->ekg2 XXX, here: mg_is_userlist_and_tree_combined() stuff */ mg_userlist_showhide(sess, TRUE); /* show */ } static void mg_userlist_toggle_cb(GtkWidget *button, gpointer userdata) { config_contacts = !config_contacts; mg_decide_userlist(window_current, FALSE); gtk_widget_grab_focus(gtk_private_ui(window_current)->input_box); } gboolean mg_populate_userlist(window_t *sess) { gtk_window_ui_t *gui; list_t l; fe_userlist_clear(sess); for (l = userlist; l; l = l->next) { struct userlist *u = l->data; int status; if (!u || !u->display || !u->uin) continue; status = ustatus_strip_descr(u->status); if (contacts_order[status] < 0 || contacts_order[status] > 4) continue; fe_userlist_insert(sess, u); } gui = gtk_private_ui(sess); #if 0 if (sess->type == SESS_DIALOG) mg_set_access_icon(sess->gui, NULL, sess->server->is_away); else mg_set_access_icon(sess->gui, get_user_icon(sess->server, sess->me), sess->server->is_away); #endif userlist_show(sess); userlist_set_value(gtk_private_ui(sess)->user_tree, gtk_private(sess)->old_ul_value); return 0; } /* fill the irc tab with a new channel */ /* static */ void mg_populate(window_t *w) { gtk_window_ui_t *gui = w->gui; int render = TRUE; guint16 vis = gui->ul_hidden; #if 0 switch (w->type) { case SESS_DIALOG: /* show the dialog buttons */ gtk_widget_show(gui->dialogbutton_box); /* hide the chan-mode buttons */ gtk_widget_hide(gui->topicbutton_box); /* hide the userlist */ mg_decide_userlist(w, FALSE); break; case SESS_SERVER: if (prefs.chanmodebuttons) gtk_widget_show(gui->topicbutton_box); /* hide the dialog buttons */ gtk_widget_hide(gui->dialogbutton_box); /* hide the userlist */ mg_decide_userlist(w, FALSE); default: /* hide the dialog buttons */ gtk_widget_hide(gui->dialogbutton_box); if (prefs.chanmodebuttons) gtk_widget_show(gui->topicbutton_box); /* show the userlist */ mg_decide_userlist(w, FALSE); } #else gtk_editable_set_editable(GTK_EDITABLE(gui->topic_entry), FALSE); /* it won't be GTK_EDITABLE() but for now... */ mg_decide_userlist(w, FALSE); #endif /* move to THE irc tab */ if (gui->is_tab) gtk_notebook_set_current_page(GTK_NOTEBOOK(gui->note_book), 0); /* xtext size change? Then don't render, wait for the expose caused by showing/hidding the userlist */ if (vis != gui->ul_hidden && gui->user_box->allocation.width > 1) render = FALSE; gtk_xtext_buffer_show(GTK_XTEXT(gui->xtext), w->buffer, render); if (gui->is_tab) gtk_widget_set_sensitive(gui->menu, TRUE); mg_focus(w); fe_set_title(w); fe_userlist_numbers(w); #if 0 /* menu items */ GTK_CHECK_MENU_ITEM(gui->menu_item[MENU_ID_AWAY])->active = w->server->is_away; gtk_widget_set_sensitive(gui->menu_item[MENU_ID_AWAY], w->server->connected); gtk_widget_set_sensitive(gui->menu_item[MENU_ID_JOIN], w->server->end_of_motd); #endif gtk_widget_set_sensitive(gui->menu_item[MENU_ID_DISCONNECT], (sess && sess->state == GG_STATE_CONNECTED) || reconnect_timer); mg_set_topic_tip(w); #if 0 plugin_emit_dummy_print(w, "Focus Tab"); #endif } #if 0 void mg_bring_tofront_sess(session *sess) { /* IRC tab or window */ if (sess->gui->is_tab) chan_focus(sess->res->tab); else gtk_window_present(GTK_WINDOW(sess->gui->window)); } void mg_bring_tofront(GtkWidget *vbox) { /* non-IRC tab or window */ chan *ch; ch = g_object_get_data(G_OBJECT(vbox), "ch"); if (ch) chan_focus(ch); else gtk_window_present(GTK_WINDOW(gtk_widget_get_toplevel(vbox))); } #endif void mg_switch_page(int relative, int num) { if (mg_gui) chanview_move_focus(mg_gui->chanview, relative, num); } /* a toplevel IRC window was destroyed */ static void mg_topdestroy_cb(GtkWidget *win, window_t *sess) { #warning "xchat->ekg2: mg_topdestroy_cb() BIG XXX" printf("mg_topdestroy_cb() XXX\n"); #if 0 /* printf("enter mg_topdestroy. sess %p was destroyed\n", sess);*/ /* kill the text buffer */ gtk_xtext_buffer_free(gtk_private(sess)->buffer); #if 0 /* kill the user list */ g_object_unref(G_OBJECT(sess->res->user_model)); #endif gtk_window_kill(sess); /* XXX, session_free(sess) */ #endif } #if 0 /* cleanup an IRC tab */ static void mg_ircdestroy(session *sess) { GSList *list; /* kill the text buffer */ gtk_xtext_buffer_free(sess->res->buffer); /* kill the user list */ g_object_unref(G_OBJECT(sess->res->user_model)); session_free(sess); /* tell xchat.c about it */ if (mg_gui == NULL) { /* puts("-> mg_gui is already NULL");*/ return; } list = sess_list; while (list) { sess = list->data; if (sess->gui->is_tab) { /* puts("-> some tabs still remain");*/ return; } list = list->next; } /* puts("-> no tabs left, killing main tabwindow");*/ gtk_widget_destroy(mg_gui->window); active_tab = NULL; mg_gui = NULL; parent_window = NULL; } #endif void mg_tab_close(window_t *sess) { #warning "xchat->ekg2: mg_tab_close() XXX" if (chan_remove(gtk_private(sess)->tab, FALSE)) #if 0 mg_ircdestroy(sess); #else ; #endif } #if 0 static void mg_traymsg_cb(GtkCheckMenuItem * item, session *sess) { sess->tray = FALSE; if (item->active) sess->tray = TRUE; } static void mg_hidejp_cb(GtkCheckMenuItem * item, session *sess) { sess->hide_join_part = TRUE; if (item->active) sess->hide_join_part = FALSE; } #endif static void mg_menu_destroy(GtkWidget *menu, gpointer userdata) { gtk_widget_destroy(menu); g_object_unref(menu); } void mg_create_icon_item(char *label, char *stock, GtkWidget *menu, void *callback, void *userdata) { GtkWidget *item; item = create_icon_menu(label, stock, TRUE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(callback), userdata); gtk_widget_show(item); } void mg_open_quit_dialog(gboolean minimize_button) { static GtkWidget *dialog = NULL; GtkWidget *dialog_vbox1; GtkWidget *table1; GtkWidget *image; GtkWidget *checkbutton1; GtkWidget *label; GtkWidget *dialog_action_area1; GtkWidget *button; char *text; if (dialog) { gtk_window_present(GTK_WINDOW(dialog)); return; } if (!gui_quit_dialog_config) { ekg_exit(); return; } if (config_save_question == 1) { #warning "Display question if user want to /save config" /* if (config_changed) format_find("config_changed") else if (config_keep_reason && reason_changed) format_find("quit_keep_reason"); */ config_save_question = 0; } #warning "xchat->ekg2 XXX" /* xchat count dcc's + connected network, and display warning about it. * * "Are you sure you want to quit?\n * "You are connected to %i IRC networks." * "Some file transfers are still active." */ dialog = gtk_dialog_new(); gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); gtk_window_set_title(GTK_WINDOW(dialog), "Wyjsc z ekg?"); gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent_window)); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); dialog_vbox1 = GTK_DIALOG(dialog)->vbox; gtk_widget_show(dialog_vbox1); table1 = gtk_table_new(2, 2, FALSE); gtk_widget_show(table1); gtk_box_pack_start(GTK_BOX(dialog_vbox1), table1, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(table1), 6); gtk_table_set_row_spacings(GTK_TABLE(table1), 12); gtk_table_set_col_spacings(GTK_TABLE(table1), 12); image = gtk_image_new_from_stock("gtk-dialog-warning", GTK_ICON_SIZE_DIALOG); gtk_widget_show(image); gtk_table_attach(GTK_TABLE(table1), image, 0, 1, 0, 1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); checkbutton1 = gtk_check_button_new_with_mnemonic("Nie pytaj nastepnym razem."); gtk_widget_show(checkbutton1); gtk_table_attach(GTK_TABLE(table1), checkbutton1, 0, 2, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 4); text = saprintf("%s\n", "Czy na pewno chcesz wyjsc?"); label = gtk_label_new(text); xfree(text); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, 0, 1, (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK), 0, 0); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); dialog_action_area1 = GTK_DIALOG(dialog)->action_area; gtk_widget_show(dialog_action_area1); gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area1), GTK_BUTTONBOX_END); if (minimize_button) { button = gtk_button_new_with_mnemonic("Minimalizuj do ikony"); gtk_widget_show(button); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, 1); } button = gtk_button_new_from_stock("gtk-cancel"); gtk_widget_show(button); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL); gtk_widget_grab_focus(button); button = gtk_button_new_from_stock("gtk-quit"); gtk_widget_show(button); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, 0); gtk_widget_show(dialog); switch (gtk_dialog_run(GTK_DIALOG(dialog))) { case 0: #if 0 if (GTK_TOGGLE_BUTTON(checkbutton1)->active) gui_quit_dialog_config = 0; xchat_exit(); #endif ekg_exit(); break; case 1: /* minimize to tray */ #if 0 if (GTK_TOGGLE_BUTTON(checkbutton1)->active) { gui_tray_flags_config |= 1; /*prefs.gui_quit_dialog = 0; */ } tray_toggle_visibility(TRUE); #endif break; } gtk_widget_destroy(dialog); dialog = NULL; } void mg_close_sess(window_t *sess) { if (sess == window_status) { /* status window? */ mg_open_quit_dialog(FALSE); return; } ui_gtk_window_kill(sess, 1); /* fe_close_window() */ } static int mg_chan_remove(chan * ch) { /* remove the tab from chanview */ chan_remove(ch, TRUE); /* any tabs left? */ if (chanview_get_size(mg_gui->chanview) < 1) { /* if not, destroy the main tab window */ gtk_widget_destroy(mg_gui->window); #if DARK current_tab = NULL; #endif active_tab = NULL; mg_gui = NULL; parent_window = NULL; return TRUE; } return FALSE; } /* the "X" close button has been pressed (tab-view) */ static void mg_xbutton_cb(chanview * cv, chan * ch, int tag, gpointer userdata) { printf("mg_xbutoon_cb(%p) [%d [TAG_WINDOW: %d]\n", userdata, tag, TAG_WINDOW); if (tag == TAG_WINDOW) /* irc tab */ mg_close_sess(userdata); #warning "xchat->ekg2, removed support for generic tabs" } static void mg_detach_tab_cb(GtkWidget *item, chan * ch) { if (chan_get_tag(ch) == TAG_WINDOW) { /* IRC tab */ /* userdata is session * */ mg_link_irctab(chan_get_userdata(ch), 1); return; } #warning "xchat->ekg2, removed support for generic tabs" } static void mg_destroy_tab_cb(GtkWidget *item, chan * ch) { /* treat it just like the X button press */ mg_xbutton_cb(mg_gui->chanview, ch, chan_get_tag(ch), chan_get_userdata(ch)); } static int key_action_insert(GtkWidget *wid, char *buf) { int tmp_pos; if (!buf) return 1; tmp_pos = gtk_editable_get_position(GTK_EDITABLE(wid)); gtk_editable_insert_text(GTK_EDITABLE(wid), buf, strlen(buf), &tmp_pos); gtk_editable_set_position(GTK_EDITABLE(wid), tmp_pos); return 2; } static void mg_color_insert(GtkWidget *item, gpointer userdata) { int num = GPOINTER_TO_INT(userdata); char buf[3]; if (!num) { printf("mg_color_insert() stub!\n"); return; } switch (num) { case 2: case 20: case 31: buf[0] = num; buf[1] = '\0'; break; default: /* kolorki -> Ctrl-R + kolorek */ buf[0] = 18; buf[1] = num; buf[2] = '\0'; } key_action_insert(window_current->gui->input_box, buf); } static void mg_markup_item(GtkWidget *menu, char *text, int arg) { GtkWidget *item; item = gtk_menu_item_new_with_label(""); gtk_label_set_markup(GTK_LABEL(GTK_BIN(item)->child), text); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(mg_color_insert), GINT_TO_POINTER(arg)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); } GtkWidget * mg_submenu(GtkWidget *menu, char *text) { GtkWidget *submenu, *item; item = gtk_menu_item_new_with_mnemonic(text); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); submenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); gtk_widget_show(submenu); return submenu; } static void mg_create_color_menu(GtkWidget *menu, window_t *sess) { GtkWidget *submenu; GtkWidget *subsubmenu; char buf[256]; int i; submenu = mg_submenu(menu, "Wstaw atrybut lub kolorek"); mg_markup_item(submenu, "Pogrubiony", 2); /* Ctrl-B */ mg_markup_item(submenu, "Podkreslony", 31); /* Ctrl-_ */ mg_markup_item(submenu, "Kursywa", 20); /* Ctrl-T */ mg_markup_item(submenu, "Normalny", 0); /* XXX XXX */ subsubmenu = mg_submenu(submenu, "Podstawowe kolory:"); for (i = 0; i < 16; i++) { sprintf(buf, "%c " " ", default_color_map[i].color, default_color_map[i].r, default_color_map[i].g, default_color_map[i].b); mg_markup_item(subsubmenu, buf, default_color_map[i].color); } subsubmenu = mg_submenu(submenu, "Kolory gg:"); for (i = 16; i < 26; i++) { sprintf(buf, "%c " " ", default_color_map[i].color, default_color_map[i].r, default_color_map[i].g, default_color_map[i].b); mg_markup_item(subsubmenu, buf, default_color_map[i].color); } } static gboolean mg_tab_contextmenu_cb(chanview * cv, chan * ch, int tag, gpointer ud, GdkEventButton * event) { GtkWidget *menu, *item; window_t *sess = ud; /* shift-click to close a tab */ if ((event->state & GDK_SHIFT_MASK) && event->type == GDK_BUTTON_PRESS) { mg_xbutton_cb(cv, ch, tag, ud); return FALSE; } if (event->button != 3) return FALSE; menu = gtk_menu_new(); if (tag == TAG_WINDOW) { char buf[256]; const char *w_target = gtk_window_target(sess); char *target = g_markup_escape_text(w_target[0] ? w_target : "", -1); snprintf(buf, sizeof(buf), "%s", target); g_free(target); item = gtk_menu_item_new_with_label(""); gtk_label_set_markup(GTK_LABEL(GTK_BIN(item)->child), buf); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); #if 0 /* separator */ item = gtk_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* i tutaj rozne rzeczy ktore moga byc TRUE/FALSE * przyklad: */ static void przykladowy_callback(GtkCheckMenuItem *item, window_t *sess) { if (item->active) sess->beep = TRUE; else sess->beep = FALSE; } /* menu_toggle_item("tekst", menu, przykladowy_callback, sess, aktualna_wartosc_tego_czegos); */ #endif } /* separator */ item = gtk_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); mg_create_icon_item("_Zamknij okno", GTK_STOCK_CLOSE, menu, mg_destroy_tab_cb, ch); mg_create_icon_item("_Okno plywajace", GTK_STOCK_REDO, menu, mg_detach_tab_cb, ch); #if 0 if (sess && tabmenu_list) menu_create(menu, tabmenu_list, sess->channel, FALSE); menu_add_plugin_items(menu, "\x4$TAB", sess->channel); #endif if (event->window) gtk_menu_set_screen(GTK_MENU(menu), gdk_drawable_get_screen(event->window)); g_object_ref(menu); g_object_ref_sink(menu); g_object_unref(menu); g_signal_connect(G_OBJECT(menu), "selection-done", G_CALLBACK(mg_menu_destroy), NULL); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, event->time); return TRUE; } /* add a tabbed channel */ static void mg_add_chan(window_t *sess) { GdkPixbuf *icon = NULL; /* pix_channel || pix_server || pix_dialog */ gtk_private(sess)->tab = chanview_add(gtk_private_ui(sess)->chanview, gtk_window_target(sess), /* sess->session, */ sess, FALSE, TAG_WINDOW, icon); if (plain_list == NULL) mg_create_tab_colors(); chan_set_color(gtk_private(sess)->tab, plain_list); if (gtk_private(sess)->buffer == NULL) { gtk_private(sess)->buffer = gtk_xtext_buffer_new(GTK_XTEXT(gtk_private_ui(sess)->xtext)); gtk_xtext_set_time_stamp(gtk_private(sess)->buffer, config_timestamp_show); gtk_private(sess)->user_model = userlist_create_model(); } } /* mg_userlist_button() do przemyslenia */ /* mg_create_userlistbuttons() */ #if 0 static void mg_topic_cb(GtkWidget *entry, gpointer userdata) { session *sess = current_sess; char *text; if (sess->channel[0] && sess->server->connected && sess->type == SESS_CHANNEL) { text = GTK_ENTRY(entry)->text; if (text[0] == 0) text = NULL; sess->server->p_topic(sess->server, sess->channel, text); } else gtk_entry_set_text(GTK_ENTRY(entry), ""); /* restore focus to the input widget, where the next input will most likely be */ gtk_widget_grab_focus(sess->gui->input_box); } #endif static void mg_tabwindow_kill_cb(GtkWidget *win, gpointer userdata) { #if 0 GSList *list, *next; session *sess; /* puts("enter mg_tabwindow_kill_cb");*/ xchat_is_quitting = TRUE; /* see if there's any non-tab windows left */ list = sess_list; while (list) { sess = list->data; next = list->next; if (!sess->gui->is_tab) { xchat_is_quitting = FALSE; /* puts("-> will not exit, some toplevel windows left");*/ } else { mg_ircdestroy(sess); } list = next; } current_tab = NULL; active_tab = NULL; mg_gui = NULL; parent_window = NULL; #endif } static GtkWidget *mg_changui_destroy(window_t *sess) { GtkWidget *ret = NULL; if (gtk_private_ui(sess)->is_tab) { /* avoid calling the "destroy" callback */ g_signal_handlers_disconnect_by_func(G_OBJECT(gtk_private_ui(sess)->window), mg_tabwindow_kill_cb, 0); /* remove the tab from the chanview */ if (!mg_chan_remove(gtk_private(sess)->tab)) /* if the window still exists, restore the signal handler */ g_signal_connect(G_OBJECT(gtk_private_ui(sess)->window), "destroy", G_CALLBACK(mg_tabwindow_kill_cb), 0); } else { /* avoid calling the "destroy" callback */ g_signal_handlers_disconnect_by_func(G_OBJECT(gtk_private_ui(sess)->window), mg_topdestroy_cb, sess); /*gtk_widget_destroy (sess->gui->window); */ /* don't destroy until the new one is created. Not sure why, but */ /* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */ /* assertion `GDK_IS_COLORMAP (cmap)' failed */ ret = gtk_private_ui(sess)->window; free(gtk_private_ui(sess)); gtk_private(sess)->gui = NULL; } return ret; } static void mg_link_irctab(window_t *sess, int focus) { GtkWidget *win; if (gtk_private_ui(sess)->is_tab) { win = mg_changui_destroy(sess); mg_changui_new(sess, 0, focus); mg_populate(sess); #if 0 xchat_is_quitting = FALSE; #endif if (win) gtk_widget_destroy(win); return; } win = mg_changui_destroy(sess); mg_changui_new(sess, 1, focus); /* the buffer is now attached to a different widget */ ((xtext_buffer *) sess->buffer)->xtext = (GtkXText *) sess->gui->xtext; if (win) gtk_widget_destroy(win); } static void mg_detach(window_t *sess, int mode) { switch (mode) { /* detach only */ case 1: if (sess->gui->is_tab) mg_link_irctab(sess, 1); break; /* attach only */ case 2: if (!sess->gui->is_tab) mg_link_irctab(sess, 1); break; /* toggle */ default: mg_link_irctab(sess, 1); } } static void mg_apply_entry_style(GtkWidget *entry) { gtk_widget_modify_base(entry, GTK_STATE_NORMAL, &colors[COL_BG]); gtk_widget_modify_text(entry, GTK_STATE_NORMAL, &colors[COL_FG]); gtk_widget_modify_font(entry, input_style->font_desc); } #if 0 static void mg_dialog_button_cb(GtkWidget *wid, char *cmd) { /* the longest cmd is 12, and the longest nickname is 64 */ char buf[128]; char *host = ""; char *topic; topic = (char *)(GTK_ENTRY(gtk_private(window_current)->gui->topic_entry)->text); topic = strrchr(topic, '@'); if (topic) host = topic + 1; auto_insert(buf, sizeof(buf), cmd, 0, 0, "", "", "", server_get_network(current_sess->server, TRUE), host, "", current_sess->channel); handle_command(current_sess, buf, TRUE); /* dirty trick to avoid auto-selection */ SPELL_ENTRY_SET_EDITABLE(current_sess->gui->input_box, FALSE); gtk_widget_grab_focus(current_sess->gui->input_box); SPELL_ENTRY_SET_EDITABLE(current_sess->gui->input_box, TRUE); } static void mg_dialog_button(GtkWidget *box, char *name, char *cmd) { GtkWidget *wid; wid = gtk_button_new_with_label(name); gtk_box_pack_start(GTK_BOX(box), wid, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wid), "clicked", G_CALLBACK(mg_dialog_button_cb), cmd); gtk_widget_set_size_request(wid, -1, 0); } static void mg_create_dialogbuttons(GtkWidget *box) { struct popup *pop; GSList *list = dlgbutton_list; while (list) { pop = list->data; if (pop->cmd[0]) mg_dialog_button(box, pop->name, pop->cmd); list = list->next; } } #endif static void mg_create_topicbar(window_t *sess, GtkWidget *box) { GtkWidget *hbox, *topic, *bbox; gtk_window_ui_t *gui = gtk_private_ui(sess); gui->topic_bar = hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(box), hbox, 0, 0, 0); if (!gui->is_tab) gtk_private(sess)->tab = NULL; gui->topic_entry = topic = gtk_entry_new(); gtk_widget_set_name(topic, "xchat-inputbox"); gtk_container_add(GTK_CONTAINER(hbox), topic); #if 0 g_signal_connect(G_OBJECT(topic), "activate", G_CALLBACK(mg_topic_cb), 0); #endif if (style_inputbox_config) mg_apply_entry_style(topic); gui->topicbutton_box = bbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), bbox, 0, 0, 0); gui->dialogbutton_box = bbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), bbox, 0, 0, 0); #if 0 mg_create_dialogbuttons(bbox); #endif if (!paned_userlist_config) gtkutil_button(hbox, GTK_STOCK_GOTO_LAST, "Pokaz/Ukryj list kontaktow", mg_userlist_toggle_cb, 0, 0); } /* check if a word is clickable */ static int mg_word_check(GtkWidget *xtext, char *word, int len) { #warning "xchat->ekg2: mg_word_check() nice functionality XXX" return 0; } /* mouse click inside text area */ static void mg_word_clicked(GtkWidget *xtext, char *word, GdkEventButton * even) { #warning "xchat->ekg2: mg_word_clicked() nice functionality XXX" } void mg_update_xtext(GtkWidget *wid) { GtkXText *xtext = GTK_XTEXT(wid); gtk_xtext_set_palette(xtext, colors); gtk_xtext_set_max_lines(xtext, config_backlog_size); gtk_xtext_set_tint(xtext, tint_red_config, tint_green_config, tint_blue_config); // gtk_xtext_set_background (xtext, channelwin_pix, transparent_config); gtk_xtext_set_wordwrap(xtext, wordwrap_config); gtk_xtext_set_show_marker(xtext, show_marker_config); gtk_xtext_set_show_separator(xtext, indent_nicks_config ? show_separator_config : 0); gtk_xtext_set_indent(xtext, indent_nicks_config); if (!gtk_xtext_set_font(xtext, font_normal_config)) { printf("Failed to open any font. I'm out of here!"); /* FE_MSG_WAIT | FE_MSG_ERROR */ exit(1); } gtk_xtext_refresh(xtext, FALSE); } /* handle errors reported by xtext */ static void mg_xtext_error(int type) { printf("mg_xtext_error() %d\n", type); /* @ type == 0 "Unable to set transparent background!\n\n" * "You may be using a non-compliant window\n" * "manager that is not currently supported.\n"), FE_MSG_WARN); * * config_transparent = 0; */ } static void mg_create_textarea(window_t *sess, GtkWidget *box) { GtkWidget *inbox, *vbox, *frame; GtkXText *xtext; gtk_window_ui_t *gui = gtk_private_ui(sess); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(box), vbox); inbox = gtk_hbox_new(FALSE, SCROLLBAR_SPACING); gtk_container_add(GTK_CONTAINER(vbox), inbox); frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(inbox), frame); gui->xtext = gtk_xtext_new(colors, TRUE); xtext = GTK_XTEXT(gui->xtext); gtk_xtext_set_max_indent(xtext, max_auto_indent_config); gtk_xtext_set_thin_separator(xtext, thin_separator_config); gtk_xtext_set_error_function(xtext, mg_xtext_error); gtk_xtext_set_urlcheck_function(xtext, mg_word_check); gtk_xtext_set_max_lines(xtext, config_backlog_size); gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(xtext)); mg_update_xtext(GTK_WIDGET(xtext)); g_signal_connect(G_OBJECT(xtext), "word_click", G_CALLBACK(mg_word_clicked), NULL); gui->vscrollbar = gtk_vscrollbar_new(GTK_XTEXT(xtext)->adj); gtk_box_pack_start(GTK_BOX(inbox), gui->vscrollbar, FALSE, TRUE, 0); #warning "xchat->ekg2: g_signal_connect() \"drag_begin\", \"drag_drop\", \"drag_motion\", \"drag_end\", \"drag_data_received\" && gtk_drag_dest_set() do zaimplementowania" } static void mg_create_userlist(gtk_window_ui_t *gui, GtkWidget *box) { GtkWidget *frame, *ulist, *vbox; vbox = gtk_vbox_new(0, 1); gtk_container_add(GTK_CONTAINER(box), vbox); frame = gtk_frame_new(NULL); if (!(gui_tweaks_config & 1)) gtk_box_pack_start(GTK_BOX(vbox), frame, 0, 0, GUI_SPACING); gui->namelistinfo = gtk_label_new(NULL); gtk_container_add(GTK_CONTAINER(frame), gui->namelistinfo); gui->user_tree = ulist = userlist_create(vbox); #if 0 if (prefs.style_namelistgad) { gtk_widget_set_style(ulist, input_style); gtk_widget_modify_base(ulist, GTK_STATE_NORMAL, &colors[COL_BG]); } #endif } static void mg_leftpane_cb(GtkPaned * pane, GParamSpec * param, gtk_window_ui_t* gui) { gui_pane_left_size_config = gtk_paned_get_position(pane); } static void mg_rightpane_cb(GtkPaned * pane, GParamSpec * param, gtk_window_ui_t* gui) { int handle_size; /* if (pane->child1 == NULL || (!GTK_WIDGET_VISIBLE (pane->child1))) return; if (pane->child2 == NULL || (!GTK_WIDGET_VISIBLE (pane->child2))) return;*/ gtk_widget_style_get(GTK_WIDGET(pane), "handle-size", &handle_size, NULL); /* record the position from the RIGHT side */ gui_pane_right_size_config = GTK_WIDGET(pane)->allocation.width - gtk_paned_get_position(pane) - handle_size; } static gboolean mg_add_pane_signals(gtk_window_ui_t* gui) { g_signal_connect(G_OBJECT(gui->hpane_right), "notify::position", G_CALLBACK(mg_rightpane_cb), gui); g_signal_connect(G_OBJECT(gui->hpane_left), "notify::position", G_CALLBACK(mg_leftpane_cb), gui); return FALSE; } static void mg_create_center(window_t *sess, gtk_window_ui_t *gui, GtkWidget *box) { GtkWidget *vbox, *hbox, *book; /* sep between top and bottom of left side */ gui->vpane_left = gtk_vpaned_new(); /* sep between top and bottom of right side */ gui->vpane_right = gtk_vpaned_new(); /* sep between left and xtext */ gui->hpane_left = gtk_hpaned_new(); gtk_paned_set_position(GTK_PANED(gui->hpane_left), gui_pane_left_size_config); /* sep between xtext and right side */ gui->hpane_right = gtk_hpaned_new(); if (gui_tweaks_config & 4) { gtk_paned_pack2(GTK_PANED(gui->hpane_left), gui->vpane_left, FALSE, TRUE); gtk_paned_pack1(GTK_PANED(gui->hpane_left), gui->hpane_right, TRUE, TRUE); } else { gtk_paned_pack1(GTK_PANED(gui->hpane_left), gui->vpane_left, FALSE, TRUE); gtk_paned_pack2(GTK_PANED(gui->hpane_left), gui->hpane_right, TRUE, TRUE); } gtk_paned_pack2(GTK_PANED(gui->hpane_right), gui->vpane_right, FALSE, TRUE); gtk_container_add(GTK_CONTAINER(box), gui->hpane_left); gui->note_book = book = gtk_notebook_new(); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(book), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(book), FALSE); gtk_paned_pack1(GTK_PANED(gui->hpane_right), book, TRUE, TRUE); hbox = gtk_hbox_new(FALSE, 0); gtk_paned_pack1(GTK_PANED(gui->vpane_right), hbox, FALSE, TRUE); mg_create_userlist(gui, hbox); gui->user_box = hbox; vbox = gtk_vbox_new(FALSE, 3); gtk_notebook_append_page(GTK_NOTEBOOK(book), vbox, NULL); mg_create_topicbar(sess, vbox); mg_create_textarea(sess, vbox); mg_create_entry(sess, vbox); g_idle_add ((GSourceFunc)mg_add_pane_signals, gui); } /* make sure chanview and userlist positions are sane */ static void mg_sanitize_positions(int *cv, int *ul) { if (tab_layout_config == 2) { /* treeview can't be on TOP or BOTTOM */ if (*cv == POS_TOP || *cv == POS_BOTTOM) *cv = POS_TOPLEFT; } /* userlist can't be on TOP or BOTTOM */ if (*ul == POS_TOP || *ul == POS_BOTTOM) *ul = POS_TOPRIGHT; /* can't have both in the same place */ if (*cv == *ul) { *cv = POS_TOPRIGHT; if (*ul == POS_TOPRIGHT) *cv = POS_BOTTOMRIGHT; } } static void mg_place_userlist_and_chanview_real(gtk_window_ui_t *gui, GtkWidget *userlist, GtkWidget *chanview) { int unref_userlist = FALSE; int unref_chanview = FALSE; /* first, remove userlist/treeview from their containers */ if (userlist && userlist->parent) { g_object_ref(userlist); gtk_container_remove(GTK_CONTAINER(userlist->parent), userlist); unref_userlist = TRUE; } if (chanview && chanview->parent) { g_object_ref(chanview); gtk_container_remove(GTK_CONTAINER(chanview->parent), chanview); unref_chanview = TRUE; } if (chanview) { /* incase the previous pos was POS_HIDDEN */ gtk_widget_show(chanview); gtk_table_set_row_spacing(GTK_TABLE(gui->main_table), 1, 0); gtk_table_set_row_spacing(GTK_TABLE(gui->main_table), 2, 2); /* then place them back in their new positions */ switch (tab_pos_config) { case POS_TOPLEFT: gtk_paned_pack1(GTK_PANED(gui->vpane_left), chanview, FALSE, TRUE); break; case POS_BOTTOMLEFT: gtk_paned_pack2(GTK_PANED(gui->vpane_left), chanview, FALSE, TRUE); break; case POS_TOPRIGHT: gtk_paned_pack1(GTK_PANED(gui->vpane_right), chanview, FALSE, TRUE); break; case POS_BOTTOMRIGHT: gtk_paned_pack2(GTK_PANED(gui->vpane_right), chanview, FALSE, TRUE); break; case POS_TOP: gtk_table_set_row_spacing(GTK_TABLE(gui->main_table), 1, GUI_SPACING - 1); gtk_table_attach(GTK_TABLE(gui->main_table), chanview, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); break; case POS_HIDDEN: gtk_widget_hide(chanview); /* always attach it to something to avoid ref_count=0 */ if (gui_ulist_pos_config == POS_TOP) gtk_table_attach(GTK_TABLE(gui->main_table), chanview, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); else gtk_table_attach(GTK_TABLE(gui->main_table), chanview, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); break; default: /* POS_BOTTOM */ gtk_table_set_row_spacing(GTK_TABLE(gui->main_table), 2, 3); gtk_table_attach(GTK_TABLE(gui->main_table), chanview, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); } } if (userlist) { switch (gui_ulist_pos_config) { case POS_TOPLEFT: gtk_paned_pack1(GTK_PANED(gui->vpane_left), userlist, FALSE, TRUE); break; case POS_BOTTOMLEFT: gtk_paned_pack2(GTK_PANED(gui->vpane_left), userlist, FALSE, TRUE); break; case POS_BOTTOMRIGHT: gtk_paned_pack2(GTK_PANED(gui->vpane_right), userlist, FALSE, TRUE); break; /* case POS_HIDDEN: break; */ /* Hide using the VIEW menu instead */ default: /* POS_TOPRIGHT */ gtk_paned_pack1(GTK_PANED(gui->vpane_right), userlist, FALSE, TRUE); } } if (unref_chanview) g_object_unref(chanview); if (unref_userlist) g_object_unref(userlist); mg_hide_empty_boxes(gui); } static void mg_place_userlist_and_chanview(gtk_window_ui_t *gui) { GtkOrientation orientation; GtkWidget *chanviewbox = NULL; int pos; mg_sanitize_positions(&tab_pos_config, &gui_ulist_pos_config); if (gui->chanview) { pos = tab_pos_config; orientation = chanview_get_orientation(gui->chanview); if ((pos == POS_BOTTOM || pos == POS_TOP) && orientation == GTK_ORIENTATION_VERTICAL) chanview_set_orientation(gui->chanview, FALSE); else if ((pos == POS_TOPLEFT || pos == POS_BOTTOMLEFT || pos == POS_TOPRIGHT || pos == POS_BOTTOMRIGHT) && orientation == GTK_ORIENTATION_HORIZONTAL) chanview_set_orientation(gui->chanview, TRUE); chanviewbox = chanview_get_box(gui->chanview); } mg_place_userlist_and_chanview_real(gui, gui->user_box, chanviewbox); } void mg_change_layout(int type) { if (mg_gui) { /* put tabs at the bottom */ if (type == 0 && tab_pos_config != POS_BOTTOM && tab_pos_config != POS_TOP) tab_pos_config = POS_BOTTOM; mg_place_userlist_and_chanview(mg_gui); chanview_set_impl(mg_gui->chanview, type); } } static void mg_inputbox_rightclick(GtkEntry * entry, GtkWidget *menu) { mg_create_color_menu(menu, NULL); } static void mg_create_entry(window_t *sess, GtkWidget *box) { GtkWidget *hbox, *entry; gtk_window_ui_t *gui = gtk_private_ui(sess); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(box), hbox, 0, 0, 0); gui->nick_box = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gui->nick_box, 0, 0, 0); gui->nick_label = gtk_label_new(itoa(config_uin)); gtk_box_pack_end(GTK_BOX(gui->nick_box), gui->nick_label, 0, 0, 0); gui->input_box = entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(gui->input_box), 2048); g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(mg_inputbox_cb), gui); gtk_container_add(GTK_CONTAINER(hbox), entry); gtk_widget_set_name(entry, "xchat-inputbox"); g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(key_handle_key_press), NULL); g_signal_connect(G_OBJECT(entry), "focus_in_event", G_CALLBACK(mg_inputbox_focus), gui); g_signal_connect(G_OBJECT(entry), "populate_popup", G_CALLBACK(mg_inputbox_rightclick), NULL); gtk_widget_grab_focus(entry); if (style_inputbox_config) mg_apply_entry_style(entry); } static void mg_switch_tab_cb(chanview *cv, chan *ch, int tag, gpointer ud) { chan *old; window_t *sess = ud; old = active_tab; active_tab = ch; if (active_tab != old) { mg_populate(sess); ui_gtk_window_switch(sess->id); } } /* compare two tabs (for tab sorting function) */ static int mg_tabs_compare(window_t *a, window_t *b) { /* it's lik: window_new_compare() */ return (a->id - b->id); } static void mg_create_tabs(gtk_window_ui_t *gui) { gui->chanview = chanview_new(tab_layout_config, truncchans_config, tab_sort_config, tab_icons_config, style_namelistgad_config ? input_style : NULL); chanview_set_callbacks(gui->chanview, mg_switch_tab_cb, mg_xbutton_cb, mg_tab_contextmenu_cb, (void *) mg_tabs_compare); mg_place_userlist_and_chanview(gui); } static gboolean mg_tabwin_focus_cb(GtkWindow * win, GdkEventFocus * event, gpointer userdata) { #if 0 current_sess = current_tab; if (current_sess) { gtk_xtext_check_marker_visibility(GTK_XTEXT(current_sess->gui->xtext)); plugin_emit_dummy_print(current_sess, "Focus Window"); } #endif #ifdef USE_XLIB unflash_window(GTK_WIDGET(win)); #endif return FALSE; } static gboolean mg_topwin_focus_cb(GtkWindow * win, GdkEventFocus * event, window_t *sess) { #if 0 current_sess = sess; if (!sess->server->server_session) sess->server->server_session = sess; gtk_xtext_check_marker_visibility(GTK_XTEXT(current_sess->gui->xtext)); #ifdef USE_XLIB unflash_window(GTK_WIDGET(win)); #endif plugin_emit_dummy_print(sess, "Focus Window"); #endif return FALSE; } static void mg_create_menu(gtk_window_ui_t *gui, GtkWidget *table, int away_state) { GtkAccelGroup *accel_group; accel_group = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(gtk_widget_get_toplevel(table)), accel_group); g_object_unref(accel_group); gui->menu = menu_create_main(accel_group, TRUE, away_state, !gui->is_tab, gui->menu_item); gtk_table_attach(GTK_TABLE(table), gui->menu, 0, 3, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); } static void mg_create_irctab(window_t *sess, GtkWidget *table) { GtkWidget *vbox; gtk_window_ui_t *gui = gtk_private_ui(sess); vbox = gtk_vbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); mg_create_center(sess, gui, vbox); } static void mg_create_topwindow(window_t *sess) { GtkWidget *win; GtkWidget *table; win = gtkutil_window_new("ekg", NULL, mainwindow_width_config, mainwindow_height_config, 0); gtk_private_ui(sess)->window = win; gtk_container_set_border_width(GTK_CONTAINER(win), GUI_BORDER); g_signal_connect(G_OBJECT(win), "focus_in_event", G_CALLBACK(mg_topwin_focus_cb), sess); g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(mg_topdestroy_cb), sess); g_signal_connect(G_OBJECT(win), "configure_event", G_CALLBACK(mg_configure_cb), sess); palette_alloc(win); table = gtk_table_new(4, 3, FALSE); /* spacing under the menubar */ gtk_table_set_row_spacing(GTK_TABLE(table), 0, GUI_SPACING); /* left and right borders */ gtk_table_set_col_spacing(GTK_TABLE(table), 0, 1); gtk_table_set_col_spacing(GTK_TABLE(table), 1, 1); gtk_container_add(GTK_CONTAINER(win), table); mg_create_irctab(sess, table); /* vvvvv sess->server->is_away */ mg_create_menu(gtk_private_ui(sess), table, 0); if (gtk_private(sess)->buffer == NULL) { gtk_private(sess)->buffer = gtk_xtext_buffer_new(GTK_XTEXT(gtk_private_ui(sess)->xtext)); gtk_xtext_buffer_show(GTK_XTEXT(gtk_private_ui(sess)->xtext), gtk_private(sess)->buffer, TRUE); gtk_xtext_set_time_stamp(gtk_private(sess)->buffer, config_timestamp_show); sess->user_model = userlist_create_model(); } userlist_show(sess); gtk_widget_show_all(table); if (hidemenu_config) gtk_widget_hide(gtk_private_ui(sess)->menu); if (!config_header_size) gtk_widget_hide(gtk_private_ui(sess)->topic_bar); if (gui_tweaks_config & 2) gtk_widget_hide(gtk_private_ui(sess)->nick_box); mg_decide_userlist(sess, FALSE); #if DARK if (sess->type == SESS_DIALOG) { /* hide the chan-mode buttons */ gtk_widget_hide(sess->gui->topicbutton_box); } else { gtk_widget_hide(sess->gui->dialogbutton_box); if (!prefs.chanmodebuttons) gtk_widget_hide(sess->gui->topicbutton_box); } #endif mg_place_userlist_and_chanview(gtk_private_ui(sess)); gtk_widget_show(win); } static gboolean mg_tabwindow_de_cb(GtkWidget *widget, GdkEvent * event, gpointer user_data) { #if 0 if ((gui_tray_flags_config & 1) && tray_toggle_visibility(FALSE)) return TRUE; /* check for remaining toplevel windows */ list = sess_list; while (list) { sess = list->data; if (!sess->gui->is_tab) return FALSE; list = list->next; } #endif mg_open_quit_dialog(TRUE); return TRUE; } static void mg_create_tabwindow(window_t *sess) { GtkWidget *win; GtkWidget *table; win = gtkutil_window_new("ekg", NULL, mainwindow_width_config, mainwindow_height_config, 0); gtk_private_ui(sess)->window = win; gtk_window_move(GTK_WINDOW(win), mainwindow_left_config, mainwindow_top_config); if (gui_win_state_config) gtk_window_maximize(GTK_WINDOW(win)); gtk_container_set_border_width(GTK_CONTAINER(win), GUI_BORDER); g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(mg_tabwindow_de_cb), 0); g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(mg_tabwindow_kill_cb), 0); g_signal_connect(G_OBJECT(win), "focus_in_event", G_CALLBACK(mg_tabwin_focus_cb), NULL); g_signal_connect(G_OBJECT(win), "configure_event", G_CALLBACK(mg_configure_cb), NULL); g_signal_connect(G_OBJECT(win), "window_state_event", G_CALLBACK(mg_windowstate_cb), NULL); palette_alloc(win); gtk_private_ui(sess)->main_table = table = gtk_table_new(4, 3, FALSE); /* spacing under the menubar */ gtk_table_set_row_spacing(GTK_TABLE(table), 0, GUI_SPACING); /* left and right borders */ gtk_table_set_col_spacing(GTK_TABLE(table), 0, 1); gtk_table_set_col_spacing(GTK_TABLE(table), 1, 1); gtk_container_add(GTK_CONTAINER(win), table); mg_create_irctab(sess, table); mg_create_tabs(gtk_private_ui(sess)); /* vvvvvv sess->server->is_away */ mg_create_menu(gtk_private_ui(sess), table, 0); mg_focus(sess); gtk_widget_show_all(table); if (hidemenu_config) gtk_widget_hide(gtk_private_ui(sess)->menu); mg_decide_userlist(sess, FALSE); if (!config_header_size) gtk_widget_hide(gtk_private_ui(sess)->topic_bar); if (!chanmodebuttons_config) gtk_widget_hide(gtk_private_ui(sess)->topicbutton_box); if (gui_tweaks_config & 2) gtk_widget_hide(gtk_private_ui(sess)->nick_box); mg_place_userlist_and_chanview(gtk_private_ui(sess)); gtk_widget_show(win); } void mg_apply_setup(void) { int done_main = FALSE; list_t l; mg_create_tab_colors(); for (l = windows; l; l = l->next) { window_t *w = l->data; gtk_xtext_set_time_stamp(gtk_private(w)->buffer, config_timestamp_show); ((xtext_buffer *) gtk_private(w)->buffer)->needs_recalc = TRUE; if (!gtk_private_ui(w)->is_tab || !done_main) mg_place_userlist_and_chanview(gtk_private_ui(w)); if (gtk_private_ui(w)->is_tab) done_main = TRUE; } } #if 0 static chan * mg_add_generic_tab(char *name, char *title, void *family, GtkWidget *box) { chan *ch; gtk_notebook_append_page(GTK_NOTEBOOK(mg_gui->note_book), box, NULL); gtk_widget_show(box); ch = chanview_add(mg_gui->chanview, name, NULL, box, TRUE, TAG_UTIL, pix_util); chan_set_color(ch, plain_list); /* FIXME: memory leak */ g_object_set_data(G_OBJECT(box), "title", strdup(title)); g_object_set_data(G_OBJECT(box), "ch", ch); if (prefs.newtabstofront) chan_focus(ch); return ch; } #endif #if 0 void fe_clear_channel(window_t *sess) { char tbuf[CHANLEN + 6]; gtk_window_ui_t *gui = gtk_private(sess); if (gui->is_tab) { if (sess->waitchannel[0]) { if (prefs.truncchans > 2 && g_utf8_strlen(sess->waitchannel, -1) > prefs.truncchans) { /* truncate long channel names */ tbuf[0] = '('; strcpy(tbuf + 1, sess->waitchannel); g_utf8_offset_to_pointer(tbuf, prefs.truncchans)[0] = 0; strcat(tbuf, "..)"); } else { sprintf(tbuf, "(%s)", sess->waitchannel); } } else strcpy(tbuf, _("")); chan_rename(sess->res->tab, tbuf, prefs.truncchans); } if (!gui->is_tab || sess == current_tab) { gtk_entry_set_text(GTK_ENTRY(gui->topic_entry), ""); if (gui->op_xpm) { gtk_widget_destroy(gui->op_xpm); gui->op_xpm = 0; } } else { } } void fe_dlgbuttons_update(window_t *sess) { GtkWidget *box; gtk_window_ui_t *gui = gtk_private(sess); gtk_widget_destroy(gui->dialogbutton_box); gui->dialogbutton_box = box = gtk_hbox_new(0, 0); gtk_box_pack_start(GTK_BOX(gui->topic_bar), box, 0, 0, 0); gtk_box_reorder_child(GTK_BOX(gui->topic_bar), box, 3); mg_create_dialogbuttons(box); gtk_widget_show_all(box); if (current_tab && current_tab->type != SESS_DIALOG) gtk_widget_hide(current_tab->gui->dialogbutton_box); } /* fe_set_nick() nieciekawe */ #endif void fe_set_away(void) { list_t l; for (l = windows; l; l = l->next) { #if DARK window_t *w = l->data; if (!sess->gui->is_tab || sess == current_tab) { GTK_CHECK_MENU_ITEM(sess->gui->menu_item[MENU_ID_AWAY])->active = serv->is_away; /* gray out my nickname */ mg_set_myself_away(sess->gui, serv->is_away); } #endif } } void fe_set_channel(window_t *sess) { if (gtk_private(sess)->tab != NULL) chan_rename(gtk_private(sess)->tab, gtk_window_target(sess), truncchans_config); } void mg_changui_new(window_t *sess, int tab, int focus) { int first_run = FALSE; gtk_window_ui_t *gui; #if DARK struct User *user = NULL; if (!sess->server->front_session) sess->server->front_session = sess; if (!is_channel(sess->server, sess->channel)) user = userlist_find_global(sess->server, sess->channel); #endif if (!tab) { gui = xmalloc(sizeof(gtk_window_ui_t)); gui->is_tab = FALSE; sess->gui = gui; mg_create_topwindow(sess); fe_set_title(sess); #if DARK if (user && user->hostname) set_topic(sess, user->hostname); #endif return; } if (mg_gui == NULL) { first_run = TRUE; gui = &static_mg_gui; memset(gui, 0, sizeof(gtk_window_ui_t)); gui->is_tab = TRUE; sess->gui = gui; mg_create_tabwindow(sess); mg_gui = gui; parent_window = gui->window; } else { sess->gui = gui = mg_gui; gui->is_tab = TRUE; } #if 0 if (user && user->hostname) set_topic(sess, user->hostname); #endif mg_add_chan(sess); if (first_run || (newtabstofront_config == FOCUS_NEW_ONLY_ASKED && focus) || newtabstofront_config == FOCUS_NEW_ALL) chan_focus(gtk_private(sess)->tab); } #if 0 GtkWidget * mg_create_generic_tab(char *name, char *title, int force_toplevel, int link_buttons, void *close_callback, void *userdata, int width, int height, GtkWidget **vbox_ret, void *family) { GtkWidget *vbox, *win; if (tab_pos_config == POS_HIDDEN && prefs.windows_as_tabs) prefs.windows_as_tabs = 0; if (force_toplevel || !prefs.windows_as_tabs) { win = gtkutil_window_new(title, name, width, height, 3); vbox = gtk_vbox_new(0, 0); *vbox_ret = vbox; gtk_container_add(GTK_CONTAINER(win), vbox); gtk_widget_show(vbox); if (close_callback) g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(close_callback), userdata); return win; } vbox = gtk_vbox_new(0, 2); g_object_set_data(G_OBJECT(vbox), "w", GINT_TO_POINTER(width)); g_object_set_data(G_OBJECT(vbox), "h", GINT_TO_POINTER(height)); gtk_container_set_border_width(GTK_CONTAINER(vbox), 3); *vbox_ret = vbox; if (close_callback) g_signal_connect(G_OBJECT(vbox), "destroy", G_CALLBACK(close_callback), userdata); mg_add_generic_tab(name, title, family, vbox); /* if (link_buttons) { hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, 0, 0, 0); mg_create_link_buttons (hbox, ch); gtk_widget_show (hbox); }*/ return vbox; } void mg_move_tab(window_t *sess, int delta) { if (sess->gui->is_tab) chan_move(sess->res->tab, delta); } void mg_set_title(GtkWidget *vbox, char *title) { /* for non-irc tab/window only */ char *old; old = g_object_get_data(G_OBJECT(vbox), "title"); if (old) { g_object_set_data(G_OBJECT(vbox), "title", xstrdup(title)); free(old); } else { gtk_window_set_title(GTK_WINDOW(vbox), title); } } #endif /* called when a session is being killed */ void fe_close_window(window_t *sess) { if (gtk_private_ui(sess)->is_tab) mg_tab_close(sess); else gtk_widget_destroy(gtk_private_ui(sess)->window); if (gtk_private_ui(sess) != &static_mg_gui) xfree(gtk_private_ui(sess)); /* free gui, if not static */ } /* NOT COPIED: * * is_child_of() mg_handle_drop() mg_drag_begin_cb() mg_drag_end_cb() mg_drag_drop_cb() * mg_drag_motion_cb() * mg_dialog_dnd_drop() * mg_dnd_drop_file() */ /* mg_count_dccs() mg_count_networks() */ /* inne okienka, ,,generic'': * mg_link_gentab() wywolywany z mg_detach_tab_cb() * mg_close_gen() wywolywany z mg_xbutton_cb() */ ekg-1.9~pre+r2855/src/ui-gtk-palette.c000066400000000000000000000157031174410337000174140ustar00rootroot00000000000000/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * port to ekg2: * Copyright (C) 2007 Jakub Zawadzki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define GTK_DISABLE_DEPRECATED /* fix includes */ #include #include #include #include #include #include #include #include #include #include #include #include "stuff.h" #include "ui.h" #include "ui-gtk-palette.h" /* XXX, todo: colors[0..15] are ok, than colors[16..31] are not ok [duplication of above], invistigate xchat sources if they needed, fix and remove. */ #warning "XXX, colors[16..31] remove!" GdkColor colors[] = { #if XCHAT_COLORS /* colors for xtext */ {0, 0x0000, 0x0000, 0x0000}, /* 17 black [30 V] */ {0, 0xc3c3, 0x3b3b, 0x3b3b}, /* 20 red [31 V] */ {0, 0x2a3d, 0x8ccc, 0x2a3d}, /* 19 green [32 V] */ {0, 0xd999, 0xa6d3, 0x4147}, /* 24 yellow [33 V] */ {0, 0x35c2, 0x35c2, 0xb332}, /* 18 blue [34 V] */ {0, 0x8000, 0x2666, 0x7fff}, /* 22 purple [35] V */ {0, 0x199a, 0x5555, 0x5555}, /* 26 aqua [36] V */ {0, 0xcccc, 0xcccc, 0xcccc}, /* 16 white [37 V] */ {0, 0x4c4c, 0x4c4c, 0x4c4c}, /* 30 grey [30b V] */ {0, 0xc7c7, 0x3232, 0x3232}, /* 21 light red [31b V] */ {0, 0x3d70, 0xcccc, 0x3d70}, /* 25 green [32b V] */ {0, 0x6666, 0x3636, 0x1f1f}, /* 23 orange [33b V] */ {0, 0x451e, 0x451e, 0xe666}, /* 28 blue [34b V] */ {0, 0xb0b0, 0x3737, 0xb0b0}, /* 29 light purple [35b V] */ {0, 0x2eef, 0x8ccc, 0x74df}, /* 27 light aqua [36b V] */ {0, 0x9595, 0x9595, 0x9595}, /* 31 light grey [37b V] */ {0, 0xcccc, 0xcccc, 0xcccc}, /* 16 white */ {0, 0x0000, 0x0000, 0x0000}, /* 17 black */ {0, 0x35c2, 0x35c2, 0xb332}, /* 18 blue */ {0, 0x2a3d, 0x8ccc, 0x2a3d}, /* 19 green */ {0, 0xc3c3, 0x3b3b, 0x3b3b}, /* 20 red */ {0, 0xc7c7, 0x3232, 0x3232}, /* 21 light red */ {0, 0x8000, 0x2666, 0x7fff}, /* 22 purple */ {0, 0x6666, 0x3636, 0x1f1f}, /* 23 orange */ {0, 0xd999, 0xa6d3, 0x4147}, /* 24 yellow */ {0, 0x3d70, 0xcccc, 0x3d70}, /* 25 green */ {0, 0x199a, 0x5555, 0x5555}, /* 26 aqua */ {0, 0x2eef, 0x8ccc, 0x74df}, /* 27 light aqua */ {0, 0x451e, 0x451e, 0xe666}, /* 28 blue */ {0, 0xb0b0, 0x3737, 0xb0b0}, /* 29 light purple */ {0, 0x4c4c, 0x4c4c, 0x4c4c}, /* 30 grey */ {0, 0x9595, 0x9595, 0x9595}, /* 31 light grey */ {0, 0xffff, 0xffff, 0xffff}, /* 32 marktext Fore (white) */ {0, 0x3535, 0x6e6e, 0xc1c1}, /* 33 marktext Back (blue) */ {0, 0x0000, 0x0000, 0x0000}, /* 34 foreground (black) */ {0, 0xf0f0, 0xf0f0, 0xf0f0}, /* 35 background (white) */ {0, 0xcccc, 0x1010, 0x1010}, /* 36 marker line (red) */ /* colors for GUI */ {0, 0x9999, 0x0000, 0x0000}, /* 37 tab New Data (dark red) */ {0, 0x0000, 0x0000, 0xffff}, /* 38 tab Nick Mentioned (blue) */ {0, 0xffff, 0x0000, 0x0000}, /* 39 tab New Message (red) */ {0, 0x9595, 0x9595, 0x9595}, /* 40 away user (grey) */ #else /* these are from http://xchat.org/files/themes/blacktheme.zip ;) */ {0, 0x0000, 0x0000, 0x0000}, /* 17 */ {0, 0xdddd, 0x0000, 0x0000}, /* 20 */ {0, 0x0000, 0xcccc, 0x0000}, /* 19 */ {0, 0xeeee, 0xdddd, 0x2222}, /* 24 */ {0, 0x0000, 0x0000, 0xcccc}, /* 18 */ {0, 0xbbbb, 0x0000, 0xbbbb}, /* 22 */ {0, 0x0000, 0xcccc, 0xcccc}, /* 26 */ {0, 0xcf3c, 0xcf3c, 0xcf3c}, /* 16 */ {0, 0x7777, 0x7777, 0x7777}, /* 30 */ {0, 0xaaaa, 0x0000, 0x0000}, /* 21 */ {0, 0x3333, 0xdede, 0x5555}, /* 25 */ {0, 0xffff, 0xaaaa, 0x0000}, /* 23 */ {0, 0x0000, 0x0000, 0xffff}, /* 28 */ {0, 0xeeee, 0x2222, 0xeeee}, /* 29 */ {0, 0x3333, 0xeeee, 0xffff}, /* 27 */ {0, 0x9999, 0x9999, 0x9999}, /* 31 */ /* duplicate */ {0, 0xcf3c, 0xcf3c, 0xcf3c}, {0, 0x0000, 0x0000, 0x0000}, {0, 0x0000, 0x0000, 0xcccc}, {0, 0x0000, 0xcccc, 0x0000}, {0, 0xdddd, 0x0000, 0x0000}, {0, 0xaaaa, 0x0000, 0x0000}, {0, 0xbbbb, 0x0000, 0xbbbb}, {0, 0xffff, 0xaaaa, 0x0000}, {0, 0xeeee, 0xdddd, 0x2222}, {0, 0x3333, 0xdede, 0x5555}, {0, 0x0000, 0xcccc, 0xcccc}, {0, 0x3333, 0xeeee, 0xffff}, {0, 0x0000, 0x0000, 0xffff}, {0, 0xeeee, 0x2222, 0xeeee}, {0, 0x7777, 0x7777, 0x7777}, {0, 0x9999, 0x9999, 0x9999}, {0, 0x0000, 0x0000, 0x0000}, {0, 0xa4a4, 0xdfdf, 0xffff}, {0, 0xdf3c, 0xdf3c, 0xdf3c}, {0, 0x0000, 0x0000, 0x0000}, {0, 0xcccc, 0x1010, 0x1010}, {0, 0x8c8c, 0x1010, 0x1010}, {0, 0x0000, 0x0000, 0xffff}, {0, 0xf5f5, 0x0000, 0x0000}, {0, 0x9999, 0x9999, 0x9999}, #endif }; #define MAX_COL 40 void palette_alloc(GtkWidget *widget) { int i; static int done_alloc = FALSE; GdkColormap *cmap; if (!done_alloc) { /* don't do it again */ done_alloc = TRUE; cmap = gtk_widget_get_colormap(widget); for (i = MAX_COL; i >= 0; i--) gdk_colormap_alloc_color(cmap, &colors[i], FALSE, TRUE); } } GdkPixbuf *pix_ekg; GdkPixbuf *gg_pixs[STATUS_PIXBUFS]; void pixmaps_init(void) { /* Ladowanie grafik z symbolu: gdk_pixbuf_new_from_inline(-1, gg_avail, FALSE, 0); */ struct { int index; const char *path; } pix[] = { {PIXBUF_AVAIL, "gg-avail.png"}, {PIXBUF_AWAY, "gg-away.png"}, {PIXBUF_INVISIBLE, "gg-invisible.png"}, {PIXBUF_BLOCKED, "gg-blocked.png"}, {PIXBUF_NOTAVAIL, "gg-notavail.png"}, {0, NULL} }, *ppix; pix_ekg = NULL; memset(gg_pixs, 0, sizeof(gg_pixs)); for (ppix = pix; ppix->path; ++ppix) { const char *user_path = prepare_path(ppix->path, 0); gg_pixs[ppix->index] = gdk_pixbuf_new_from_file(user_path, 0); if (!gg_pixs[ppix->index]) { char buf[512]; snprintf(buf, sizeof(buf), DATADIR "/%s", ppix->path); gg_pixs[ppix->index] = gdk_pixbuf_new_from_file(buf, 0); } if (!gg_pixs[ppix->index]) printf("UWAGA: Nie znaleziono ani %s ani " DATADIR "/%s - nie bedziesz mial ikonki w userliscie\n", user_path, ppix->path); } } ekg-1.9~pre+r2855/src/ui-gtk-palette.h000066400000000000000000000011301174410337000174060ustar00rootroot00000000000000#ifndef UI_GTK_PALETTE_H #define UI_GTK_PALETTE_H extern GdkColor colors[]; #define COL_MARK_FG 32 #define COL_MARK_BG 33 #define COL_FG 34 #define COL_BG 35 #define COL_MARKER 36 #define COL_NEW_DATA 37 #define COL_HILIGHT 38 #define COL_NEW_MSG 39 #define COL_AWAY 40 void palette_alloc(GtkWidget *widget); void pixmaps_init(void); extern GdkPixbuf *pix_ekg; extern GdkPixbuf *gg_pixs[]; #define PIXBUF_AVAIL 0 #define PIXBUF_AWAY 1 #define PIXBUF_INVISIBLE 2 #define PIXBUF_BLOCKED 3 #define PIXBUF_NOTAVAIL 4 #define STATUS_PIXBUFS 5 /* AVAIL, AWAY, INVISIBLE, BLOCKED, NOTAVAIL */ #endif ekg-1.9~pre+r2855/src/ui-gtk-xtext.c000066400000000000000000003227311174410337000171340ustar00rootroot00000000000000/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * ========================================================================= * * xtext, the text widget used by X-Chat. * By Peter Zelezny . * * optimized, and rewriten to support fstring_t * By Jakub Zawadzki . */ #define TINT_VALUE 195 /* 195/255 of the brightness. */ #define MOTION_MONITOR /* URL hilights. */ #define SMOOTH_SCROLL /* line-by-line or pixel scroll? */ #define SCROLL_HACK /* use XCopyArea scroll, or full redraw? */ #undef COLOR_HILIGHT /* Color instead of underline? */ /* Italic is buggy because it assumes drawing an italic string will have identical extents to the normal font. This is only true some of the time, so we can't use this hack yet. */ #undef ITALIC /* support Italic? */ #define GDK_MULTIHEAD_SAFE #define USE_DB /* double buffer */ #define MARGIN 2 /* dont touch. */ #define REFRESH_TIMEOUT 20 #define WORDWRAP_LIMIT 24 #define USE_XLIB #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_XLIB #include #include #include #endif #include "stuff.h" #include "themes.h" #include "xmalloc.h" #include "ui-gtk-xtext.h" #define charlen(str) g_utf8_skip[*(guchar *)(str)] /* is delimiter */ #define is_del(c) (c == ' ' || c == '\n' || c == ')' || c == '(' || c == '>' || c == '<' || c == 0) #warning "XXX, ATTR_* stuff" /* is_del includes ATTR_RESET, ATTR_BOLD */ #ifdef SCROLL_HACK /* force scrolling off */ #define dontscroll(buf) (buf)->last_pixel_pos = 0x7fffffff #else #define dontscroll(buf) #endif static GtkWidgetClass *parent_class = NULL; struct textentry { struct textentry *next; struct textentry *prev; fstring_t fstr; unsigned char *str; gint16 str_width; gint16 str_len; gint16 mark_start; gint16 mark_end; gint16 indent; gint16 left_len; gint16 lines_taken; #define RECORD_WRAPS 4 guint16 wrap_offset[RECORD_WRAPS]; unsigned int mb:1; /* is multibyte? */ }; enum { WORD_CLICK, LAST_SIGNAL }; /* values for selection info */ enum { TARGET_UTF8_STRING, TARGET_STRING, TARGET_TEXT, TARGET_COMPOUND_TEXT }; static guint xtext_signals[LAST_SIGNAL]; static void gtk_xtext_render_page(GtkXText * xtext); static void gtk_xtext_calc_lines(xtext_buffer * buf, int); #if defined(USE_XLIB) || defined(WIN32) static void gtk_xtext_load_trans(GtkXText * xtext); static void gtk_xtext_free_trans(GtkXText * xtext); #endif static char *gtk_xtext_selection_get_text(GtkXText * xtext, int *len_ret); static textentry *gtk_xtext_nth(GtkXText * xtext, int line, int *subline); static void gtk_xtext_adjustment_changed(GtkAdjustment * adj, GtkXText * xtext); static int gtk_xtext_render_ents(GtkXText * xtext, textentry *, textentry *); static void gtk_xtext_recalc_widths(xtext_buffer * buf, int); static void gtk_xtext_fix_indent(xtext_buffer * buf); static int gtk_xtext_find_subline(GtkXText * xtext, textentry * ent, int line); static unsigned char *gtk_xtext_strip_color(unsigned char *text, int len, unsigned char *outbuf, int *mb_ret); /* some utility functions first */ /* gives width of a 8bit string */ static int gtk_xtext_text_width_8bit(GtkXText * xtext, unsigned char *str, int len) { int width = 0; while (len) { width += xtext->fontwidth[*str]; str++; len--; } return width; } #define xtext_draw_bg(xt,x,y,w,h) gdk_draw_rectangle(xt->draw_buf, xt->bgc,1,x,y,w,h); /* ========================================= */ /* ========== XFT 1 and 2 BACKEND ========== */ /* ========================================= */ #ifdef USE_XFT static void backend_font_close(GtkXText * xtext) { XftFontClose(GDK_WINDOW_XDISPLAY(xtext->draw_buf), xtext->font); #ifdef ITALIC XftFontClose(GDK_WINDOW_XDISPLAY(xtext->draw_buf), xtext->ifont); #endif } static void backend_init(GtkXText * xtext) { if (xtext->xftdraw == NULL) { xtext->xftdraw = XftDrawCreate(GDK_WINDOW_XDISPLAY(xtext->draw_buf), GDK_WINDOW_XWINDOW(xtext->draw_buf), GDK_VISUAL_XVISUAL(gdk_drawable_get_visual (xtext->draw_buf)), GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap (xtext->draw_buf))); XftDrawSetSubwindowMode(xtext->xftdraw, IncludeInferiors); } } static void backend_deinit(GtkXText * xtext) { if (xtext->xftdraw) { XftDrawDestroy(xtext->xftdraw); xtext->xftdraw = NULL; } } static XftFont *backend_font_open_real(Display * xdisplay, char *name, gboolean italics) { XftFont *font = NULL; PangoFontDescription *fontd; int weight, slant, screen = DefaultScreen(xdisplay); fontd = pango_font_description_from_string(name); if (pango_font_description_get_size(fontd) != 0) { weight = pango_font_description_get_weight(fontd); /* from pangoft2-fontmap.c */ if (weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_LIGHT) / 2) weight = XFT_WEIGHT_LIGHT; else if (weight < (PANGO_WEIGHT_NORMAL + 600) / 2) weight = XFT_WEIGHT_MEDIUM; else if (weight < (600 + PANGO_WEIGHT_BOLD) / 2) weight = XFT_WEIGHT_DEMIBOLD; else if (weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2) weight = XFT_WEIGHT_BOLD; else weight = XFT_WEIGHT_BLACK; slant = pango_font_description_get_style(fontd); if (slant == PANGO_STYLE_ITALIC) slant = XFT_SLANT_ITALIC; else if (slant == PANGO_STYLE_OBLIQUE) slant = XFT_SLANT_OBLIQUE; else slant = XFT_SLANT_ROMAN; font = XftFontOpen(xdisplay, screen, XFT_FAMILY, XftTypeString, pango_font_description_get_family(fontd), XFT_CORE, XftTypeBool, False, XFT_SIZE, XftTypeDouble, (double)pango_font_description_get_size(fontd) / PANGO_SCALE, XFT_WEIGHT, XftTypeInteger, weight, XFT_SLANT, XftTypeInteger, italics ? XFT_SLANT_ITALIC : slant, NULL); } pango_font_description_free(fontd); if (font == NULL) { font = XftFontOpenName(xdisplay, screen, name); if (font == NULL) font = XftFontOpenName(xdisplay, screen, "sans-11"); } return font; } static void backend_font_open(GtkXText * xtext, char *name) { Display *dis = GDK_WINDOW_XDISPLAY(xtext->draw_buf); xtext->font = backend_font_open_real(dis, name, FALSE); #ifdef ITALIC xtext->ifont = backend_font_open_real(dis, name, TRUE); #endif } inline static int backend_get_char_width(GtkXText * xtext, unsigned char *str, int *mbl_ret) { XGlyphInfo ext; if (*str < 128) { *mbl_ret = 1; return xtext->fontwidth[*str]; } *mbl_ret = charlen(str); XftTextExtentsUtf8(GDK_WINDOW_XDISPLAY(xtext->draw_buf), xtext->font, str, *mbl_ret, &ext); return ext.xOff; } static int backend_get_text_width(GtkXText * xtext, guchar * str, int len, int is_mb) { XGlyphInfo ext; if (!is_mb) return gtk_xtext_text_width_8bit(xtext, str, len); XftTextExtentsUtf8(GDK_WINDOW_XDISPLAY(xtext->draw_buf), xtext->font, str, len, &ext); return ext.xOff; } static void backend_draw_text(GtkXText * xtext, int dofill, GdkGC * gc, int x, int y, char *str, int len, int str_width, int is_mb) { /*Display *xdisplay = GDK_WINDOW_XDISPLAY (xtext->draw_buf); */ void (*draw_func) (XftDraw *, XftColor *, XftFont *, int, int, XftChar8 *, int) = (void *)XftDrawString8; XftFont *font; /* if all ascii, use String8 to avoid the conversion penalty */ if (is_mb) draw_func = (void *)XftDrawStringUtf8; if (dofill) { /* register GC xgc = GDK_GC_XGC (gc); XSetForeground (xdisplay, xgc, xtext->xft_bg->pixel); XFillRectangle (xdisplay, GDK_WINDOW_XWINDOW (xtext->draw_buf), xgc, x, y - xtext->font->ascent, str_width, xtext->fontsize);*/ XftDrawRect(xtext->xftdraw, xtext->xft_bg, x, y - xtext->font->ascent, str_width, xtext->fontsize); } font = xtext->font; #ifdef ITALIC if (xtext->italics) font = xtext->ifont; #endif draw_func(xtext->xftdraw, xtext->xft_fg, font, x, y, str, len); if (xtext->overdraw) draw_func(xtext->xftdraw, xtext->xft_fg, font, x, y, str, len); if (xtext->bold) draw_func(xtext->xftdraw, xtext->xft_fg, font, x + 1, y, str, len); } /*static void backend_set_clip (GtkXText *xtext, GdkRectangle *area) { gdk_gc_set_clip_rectangle (xtext->fgc, area); gdk_gc_set_clip_rectangle (xtext->bgc, area); } static void backend_clear_clip (GtkXText *xtext) { gdk_gc_set_clip_rectangle (xtext->fgc, NULL); gdk_gc_set_clip_rectangle (xtext->bgc, NULL); }*/ /*static void backend_set_clip (GtkXText *xtext, GdkRectangle *area) { Region reg; XRectangle rect; rect.x = area->x; rect.y = area->y; rect.width = area->width; rect.height = area->height; reg = XCreateRegion (); XUnionRectWithRegion (&rect, reg, reg); XftDrawSetClip (xtext->xftdraw, reg); XDestroyRegion (reg); gdk_gc_set_clip_rectangle (xtext->fgc, area); } static void backend_clear_clip (GtkXText *xtext) { XftDrawSetClip (xtext->xftdraw, NULL); gdk_gc_set_clip_rectangle (xtext->fgc, NULL); } */ #else /* !USE_XFT */ /* ======================================= */ /* ============ PANGO BACKEND ============ */ /* ======================================= */ static void backend_font_close(GtkXText * xtext) { pango_font_description_free(xtext->font->font); #ifdef ITALIC pango_font_description_free(xtext->font->ifont); #endif } static void backend_init(GtkXText * xtext) { if (xtext->layout == NULL) { xtext->layout = gtk_widget_create_pango_layout(GTK_WIDGET(xtext), 0); if (xtext->font) pango_layout_set_font_description(xtext->layout, xtext->font->font); } } static void backend_deinit(GtkXText * xtext) { if (xtext->layout) { g_object_unref(xtext->layout); xtext->layout = NULL; } } static PangoFontDescription *backend_font_open_real(char *name) { PangoFontDescription *font; font = pango_font_description_from_string(name); if (font && pango_font_description_get_size(font) == 0) { pango_font_description_free(font); font = NULL; /* we'll try again, with sans 11 */ } if (!font) font = pango_font_description_from_string("sans 11"); return font; } static void backend_font_open(GtkXText * xtext, char *name) { PangoLanguage *lang; PangoContext *context; PangoFontMetrics *metrics; xtext->font = &xtext->pango_font; xtext->font->font = backend_font_open_real(name); if (!xtext->font->font) { xtext->font = NULL; return; } #ifdef ITALIC xtext->font->ifont = backend_font_open_real(name); pango_font_description_set_style(xtext->font->ifont, PANGO_STYLE_ITALIC); #endif backend_init(xtext); pango_layout_set_font_description(xtext->layout, xtext->font->font); /* vte does it this way */ context = gtk_widget_get_pango_context(GTK_WIDGET(xtext)); lang = pango_context_get_language(context); metrics = pango_context_get_metrics(context, xtext->font->font, lang); xtext->font->ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; xtext->font->descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE; pango_font_metrics_unref(metrics); } static int backend_get_text_width(GtkXText * xtext, guchar * str, int len, int is_mb) { int width; if (!is_mb) return gtk_xtext_text_width_8bit(xtext, str, len); if (*str == 0) return 0; pango_layout_set_text(xtext->layout, str, len); pango_layout_get_pixel_size(xtext->layout, &width, NULL); return width; } inline static int backend_get_char_width(GtkXText * xtext, unsigned char *str, int *mbl_ret) { int width; if (*str < 128) { *mbl_ret = 1; return xtext->fontwidth[*str]; } *mbl_ret = charlen(str); pango_layout_set_text(xtext->layout, str, *mbl_ret); pango_layout_get_pixel_size(xtext->layout, &width, NULL); return width; } /* simplified version of gdk_draw_layout_line_with_colors() */ static void xtext_draw_layout_line(GdkDrawable * drawable, GdkGC * gc, gint x, gint y, PangoLayoutLine * line) { GSList *tmp_list; PangoRectangle logical_rect; gint x_off = 0; for (tmp_list = line->runs; tmp_list; tmp_list = tmp_list->next) { PangoLayoutRun *run = tmp_list->data; pango_glyph_string_extents(run->glyphs, run->item->analysis.font, NULL, &logical_rect); gdk_draw_glyphs(drawable, gc, run->item->analysis.font, x + x_off / PANGO_SCALE, y, run->glyphs); x_off += logical_rect.width; } } static void backend_draw_text(GtkXText * xtext, int dofill, GdkGC * gc, int x, int y, char *str, int len, int str_width, int is_mb) { GdkGCValues val; GdkColor col; PangoLayoutLine *line; #ifdef ITALIC if (xtext->italics) pango_layout_set_font_description(xtext->layout, xtext->font->ifont); #endif pango_layout_set_text(xtext->layout, str, len); if (dofill) { gdk_gc_get_values(gc, &val); col.pixel = val.background.pixel; gdk_gc_set_foreground(gc, &col); gdk_draw_rectangle(xtext->draw_buf, gc, 1, x, y - xtext->font->ascent, str_width, xtext->fontsize); col.pixel = val.foreground.pixel; gdk_gc_set_foreground(gc, &col); } line = pango_layout_get_lines(xtext->layout)->data; xtext_draw_layout_line(xtext->draw_buf, gc, x, y, line); if (xtext->overdraw) xtext_draw_layout_line(xtext->draw_buf, gc, x, y, line); if (xtext->bold) xtext_draw_layout_line(xtext->draw_buf, gc, x + 1, y, line); #ifdef ITALIC if (xtext->italics) pango_layout_set_font_description(xtext->layout, xtext->font->font); #endif } /*static void backend_set_clip (GtkXText *xtext, GdkRectangle *area) { gdk_gc_set_clip_rectangle (xtext->fgc, area); gdk_gc_set_clip_rectangle (xtext->bgc, area); } static void backend_clear_clip (GtkXText *xtext) { gdk_gc_set_clip_rectangle (xtext->fgc, NULL); gdk_gc_set_clip_rectangle (xtext->bgc, NULL); }*/ #endif /* !USE_PANGO */ static void xtext_set_fg(GtkXText * xtext, GdkGC * gc, int index) { GdkColor col; col.pixel = xtext->palette[index]; gdk_gc_set_foreground(gc, &col); #ifdef USE_XFT if (gc == xtext->fgc) xtext->xft_fg = &xtext->color[index]; else xtext->xft_bg = &xtext->color[index]; #endif } #ifdef USE_XFT #define xtext_set_bg(xt,gc,index) xt->xft_bg = &xt->color[index] #else static void xtext_set_bg(GtkXText * xtext, GdkGC * gc, int index) { GdkColor col; col.pixel = xtext->palette[index]; gdk_gc_set_background(gc, &col); } #endif static void gtk_xtext_init(GtkXText * xtext) { xtext->pixmap = NULL; xtext->io_tag = 0; xtext->add_io_tag = 0; xtext->scroll_tag = 0; xtext->max_lines = 0; xtext->col_back = XTEXT_BG; xtext->col_fore = XTEXT_FG; xtext->nc = 0; xtext->pixel_offset = 0; xtext->bold = FALSE; xtext->underline = FALSE; xtext->italics = FALSE; xtext->font = NULL; #ifdef USE_XFT xtext->xftdraw = NULL; #else xtext->layout = NULL; #endif xtext->jump_out_offset = 0; xtext->jump_in_offset = 0; xtext->ts_x = 0; xtext->ts_y = 0; xtext->clip_x = 0; xtext->clip_x2 = 1000000; xtext->clip_y = 0; xtext->clip_y2 = 1000000; xtext->error_function = NULL; xtext->urlcheck_function = NULL; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; xtext->render_hilights_only = FALSE; xtext->un_hilight = FALSE; xtext->recycle = FALSE; xtext->dont_render = FALSE; xtext->dont_render2 = FALSE; xtext->overdraw = FALSE; xtext->tint_red = xtext->tint_green = xtext->tint_blue = TINT_VALUE; xtext->adj = (GtkAdjustment *) gtk_adjustment_new(0, 0, 1, 1, 1, 1); g_object_ref(G_OBJECT(xtext->adj)); g_object_ref_sink(G_OBJECT(xtext->adj)); g_object_unref(G_OBJECT(xtext->adj)); xtext->vc_signal_tag = g_signal_connect(G_OBJECT(xtext->adj), "value_changed", G_CALLBACK(gtk_xtext_adjustment_changed), xtext); { static const GtkTargetEntry targets[] = { {"UTF8_STRING", 0, TARGET_UTF8_STRING}, {"STRING", 0, TARGET_STRING}, {"TEXT", 0, TARGET_TEXT}, {"COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT} }; static const gint n_targets = sizeof(targets) / sizeof(targets[0]); gtk_selection_add_targets(GTK_WIDGET(xtext), GDK_SELECTION_PRIMARY, targets, n_targets); } if (getenv("XCHAT_OVERDRAW")) xtext->overdraw = TRUE; } static void gtk_xtext_adjustment_set(xtext_buffer * buf, int fire_signal) { GtkAdjustment *adj = buf->xtext->adj; if (buf->xtext->buffer == buf) { adj->lower = 0; adj->upper = buf->num_lines; if (adj->upper == 0) adj->upper = 1; adj->page_size = (GTK_WIDGET(buf->xtext)->allocation.height - buf->xtext->font->descent) / buf->xtext->fontsize; adj->page_increment = adj->page_size; if (adj->value > adj->upper - adj->page_size) adj->value = adj->upper - adj->page_size; if (adj->value < 0) adj->value = 0; if (fire_signal) gtk_adjustment_changed(adj); } } static gint gtk_xtext_adjustment_timeout(GtkXText * xtext) { gtk_xtext_render_page(xtext); xtext->io_tag = 0; return 0; } static void gtk_xtext_adjustment_changed(GtkAdjustment * adj, GtkXText * xtext) { #ifdef SMOOTH_SCROLL if (xtext->buffer->old_value != xtext->adj->value) #else if ((int)xtext->buffer->old_value != (int)xtext->adj->value) #endif { if (xtext->adj->value >= xtext->adj->upper - xtext->adj->page_size) xtext->buffer->scrollbar_down = TRUE; else xtext->buffer->scrollbar_down = FALSE; if (xtext->adj->value + 1 == xtext->buffer->old_value || xtext->adj->value - 1 == xtext->buffer->old_value) { /* clicked an arrow? */ if (xtext->io_tag) { g_source_remove(xtext->io_tag); xtext->io_tag = 0; } gtk_xtext_render_page(xtext); } else { if (!xtext->io_tag) xtext->io_tag = g_timeout_add(REFRESH_TIMEOUT, (GSourceFunc) gtk_xtext_adjustment_timeout, xtext); } } xtext->buffer->old_value = adj->value; } GtkWidget *gtk_xtext_new(GdkColor palette[], int separator) { GtkXText *xtext = g_object_new(gtk_xtext_get_type(), NULL); xtext->separator = separator; xtext->wordwrap = TRUE; xtext->buffer = gtk_xtext_buffer_new(xtext); xtext->orig_buffer = xtext->buffer; gtk_widget_set_double_buffered(GTK_WIDGET(xtext), FALSE); gtk_xtext_set_palette(xtext, palette); return GTK_WIDGET(xtext); } static void gtk_xtext_destroy(GtkObject * object) { GtkXText *xtext = GTK_XTEXT(object); if (xtext->add_io_tag) { g_source_remove(xtext->add_io_tag); xtext->add_io_tag = 0; } if (xtext->scroll_tag) { g_source_remove(xtext->scroll_tag); xtext->scroll_tag = 0; } if (xtext->io_tag) { g_source_remove(xtext->io_tag); xtext->io_tag = 0; } if (xtext->pixmap) { #if defined(USE_XLIB) || defined(WIN32) if (xtext->transparent) gtk_xtext_free_trans(xtext); else #endif g_object_unref(xtext->pixmap); xtext->pixmap = NULL; } if (xtext->font) { backend_font_close(xtext); xtext->font = NULL; } if (xtext->adj) { g_signal_handlers_disconnect_matched(G_OBJECT(xtext->adj), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, xtext); /* gtk_signal_disconnect_by_data (GTK_OBJECT (xtext->adj), xtext); */ g_object_unref(G_OBJECT(xtext->adj)); xtext->adj = NULL; } if (xtext->bgc) { g_object_unref(xtext->bgc); xtext->bgc = NULL; } if (xtext->fgc) { g_object_unref(xtext->fgc); xtext->fgc = NULL; } if (xtext->light_gc) { g_object_unref(xtext->light_gc); xtext->light_gc = NULL; } if (xtext->dark_gc) { g_object_unref(xtext->dark_gc); xtext->dark_gc = NULL; } if (xtext->thin_gc) { g_object_unref(xtext->thin_gc); xtext->thin_gc = NULL; } if (xtext->marker_gc) { g_object_unref(xtext->marker_gc); xtext->marker_gc = NULL; } if (xtext->hand_cursor) { gdk_cursor_unref(xtext->hand_cursor); xtext->hand_cursor = NULL; } if (xtext->resize_cursor) { gdk_cursor_unref(xtext->resize_cursor); xtext->resize_cursor = NULL; } if (xtext->orig_buffer) { gtk_xtext_buffer_free(xtext->orig_buffer); xtext->orig_buffer = NULL; } if (GTK_OBJECT_CLASS(parent_class)->destroy) (*GTK_OBJECT_CLASS(parent_class)->destroy) (object); } static void gtk_xtext_unrealize(GtkWidget *widget) { backend_deinit(GTK_XTEXT(widget)); /* if there are still events in the queue, this'll avoid segfault */ gdk_window_set_user_data(widget->window, NULL); if (parent_class->unrealize) (*GTK_WIDGET_CLASS(parent_class)->unrealize) (widget); } static void gtk_xtext_realize(GtkWidget *widget) { GtkXText *xtext; GdkWindowAttr attributes; GdkGCValues val; GdkColor col; GdkColormap *cmap; GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); xtext = GTK_XTEXT(widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK #ifdef MOTION_MONITOR | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK; #else | GDK_POINTER_MOTION_MASK; #endif cmap = gtk_widget_get_colormap(widget); attributes.colormap = cmap; attributes.visual = gtk_widget_get_visual(widget); widget->window = gdk_window_new(widget->parent->window, &attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP); gdk_window_set_user_data(widget->window, widget); xtext->depth = gdk_drawable_get_visual(widget->window)->depth; val.subwindow_mode = GDK_INCLUDE_INFERIORS; val.graphics_exposures = 0; xtext->bgc = gdk_gc_new_with_values(widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->fgc = gdk_gc_new_with_values(widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->light_gc = gdk_gc_new_with_values(widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->dark_gc = gdk_gc_new_with_values(widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->thin_gc = gdk_gc_new_with_values(widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->marker_gc = gdk_gc_new_with_values(widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); /* for the separator bar (light) */ col.red = 0xffff; col.green = 0xffff; col.blue = 0xffff; gdk_colormap_alloc_color(cmap, &col, FALSE, TRUE); gdk_gc_set_foreground(xtext->light_gc, &col); /* for the separator bar (dark) */ col.red = 0x1111; col.green = 0x1111; col.blue = 0x1111; gdk_colormap_alloc_color(cmap, &col, FALSE, TRUE); gdk_gc_set_foreground(xtext->dark_gc, &col); /* for the separator bar (thinline) */ col.red = 0x8e38; col.green = 0x8e38; col.blue = 0x9f38; gdk_colormap_alloc_color(cmap, &col, FALSE, TRUE); gdk_gc_set_foreground(xtext->thin_gc, &col); /* for the marker bar (marker) */ col.pixel = xtext->palette[XTEXT_MARKER]; gdk_gc_set_foreground(xtext->marker_gc, &col); xtext_set_fg(xtext, xtext->fgc, XTEXT_FG); xtext_set_bg(xtext, xtext->fgc, XTEXT_BG); xtext_set_fg(xtext, xtext->bgc, XTEXT_BG); /* draw directly to window */ xtext->draw_buf = widget->window; #if defined(USE_XLIB) || defined(WIN32) if (xtext->transparent) { gtk_xtext_load_trans(xtext); } else #endif if (xtext->pixmap) { gdk_gc_set_tile(xtext->bgc, xtext->pixmap); gdk_gc_set_ts_origin(xtext->bgc, 0, 0); xtext->ts_x = xtext->ts_y = 0; gdk_gc_set_fill(xtext->bgc, GDK_TILED); } #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) xtext->hand_cursor = gdk_cursor_new(GDK_HAND1); xtext->resize_cursor = gdk_cursor_new(GDK_LEFT_SIDE); #else xtext->hand_cursor = gdk_cursor_new_for_display(gdk_drawable_get_display(widget->window), GDK_HAND1); xtext->resize_cursor = gdk_cursor_new_for_display(gdk_drawable_get_display(widget->window), GDK_LEFT_SIDE); #endif gdk_window_set_back_pixmap(widget->window, NULL, FALSE); widget->style = gtk_style_attach(widget->style, widget->window); backend_init(xtext); } static void gtk_xtext_size_request(GtkWidget *widget, GtkRequisition * requisition) { requisition->width = 200; requisition->height = 90; } static void gtk_xtext_size_allocate(GtkWidget *widget, GtkAllocation * allocation) { GtkXText *xtext = GTK_XTEXT(widget); int height_only = FALSE; int do_trans = TRUE; if (allocation->width == xtext->buffer->window_width) height_only = TRUE; if (allocation->x == widget->allocation.x && allocation->y == widget->allocation.y && xtext->avoid_trans) do_trans = FALSE; xtext->avoid_trans = FALSE; widget->allocation = *allocation; if (GTK_WIDGET_REALIZED(widget)) { xtext->buffer->window_width = allocation->width; xtext->buffer->window_height = allocation->height; gdk_window_move_resize(widget->window, allocation->x, allocation->y, allocation->width, allocation->height); dontscroll(xtext->buffer); /* force scrolling off */ if (!height_only) gtk_xtext_calc_lines(xtext->buffer, FALSE); else { xtext->buffer->pagetop_ent = NULL; gtk_xtext_adjustment_set(xtext->buffer, FALSE); } #if defined(USE_XLIB) || defined(WIN32) if (do_trans && xtext->transparent && xtext->shaded) { gtk_xtext_free_trans(xtext); gtk_xtext_load_trans(xtext); } #endif if (xtext->buffer->scrollbar_down) gtk_adjustment_set_value(xtext->adj, xtext->adj->upper - xtext->adj->page_size); } } static int gtk_xtext_selection_clear(xtext_buffer * buf) { textentry *ent; int ret = 0; for (ent = buf->last_ent_start; ent; ent = ent->next) { if (ent->mark_start != -1) ret = 1; ent->mark_start = -1; ent->mark_end = -1; if (ent == buf->last_ent_end) break; } return ret; } static int find_x(GtkXText * xtext, textentry * ent, unsigned char *text, int x, int indent) { int xx = indent; int i = 0; unsigned char *orig = text; int mbl; int char_width; while (*text) { mbl = 1; char_width = backend_get_char_width(xtext, text, &mbl); xx += char_width; text += mbl; if (xx >= x) return i + (orig - ent->str); i += mbl; if (text - orig >= ent->str_len) return ent->str_len; } return ent->str_len; } static int gtk_xtext_find_x(GtkXText * xtext, int x, textentry * ent, int subline, int line, int *out_of_bounds) { int indent; unsigned char *str; if (subline < 1) indent = ent->indent; else indent = xtext->buffer->indent; if (line > xtext->adj->page_size || line < 0) return 0; if (xtext->buffer->grid_dirty || line > 255) { str = ent->str + gtk_xtext_find_subline(xtext, ent, subline); if (str >= ent->str + ent->str_len) return 0; } else { if (xtext->buffer->grid_offset[line] > ent->str_len) return 0; str = ent->str + xtext->buffer->grid_offset[line]; } if (x < indent) { *out_of_bounds = 1; return (str - ent->str); } *out_of_bounds = 0; return find_x(xtext, ent, str, x, indent); } static textentry *gtk_xtext_find_char(GtkXText * xtext, int x, int y, int *off, int *out_of_bounds) { textentry *ent; int line; int subline; line = (y + xtext->pixel_offset) / xtext->fontsize; if (!(ent = gtk_xtext_nth(xtext, line + (int)xtext->adj->value, &subline))) return NULL; if (off) *off = gtk_xtext_find_x(xtext, x, ent, subline, line, out_of_bounds); return ent; } static void gtk_xtext_draw_sep(GtkXText * xtext, int y) { int x, height; GdkGC *light, *dark; if (y == -1) { y = 0; height = GTK_WIDGET(xtext)->allocation.height; } else { height = xtext->fontsize; } /* draw the separator line */ if (xtext->separator && xtext->buffer->indent) { light = xtext->light_gc; dark = xtext->dark_gc; x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (x < 1) return; if (xtext->thinline) { if (xtext->moving_separator) gdk_draw_line(xtext->draw_buf, light, x, y, x, y + height); else gdk_draw_line(xtext->draw_buf, xtext->thin_gc, x, y, x, y + height); } else { if (xtext->moving_separator) { gdk_draw_line(xtext->draw_buf, light, x - 1, y, x - 1, y + height); gdk_draw_line(xtext->draw_buf, dark, x, y, x, y + height); } else { gdk_draw_line(xtext->draw_buf, dark, x - 1, y, x - 1, y + height); gdk_draw_line(xtext->draw_buf, light, x, y, x, y + height); } } } } static void gtk_xtext_draw_marker(GtkXText * xtext, textentry * ent, int y) { int x, width, render_y; if (!xtext->marker) return; if (xtext->buffer->marker_pos == ent) { render_y = y + xtext->font->descent; } else if (xtext->buffer->marker_pos == ent->next && ent->next != NULL) { render_y = y + xtext->font->descent + xtext->fontsize * ent->lines_taken; } else return; x = 0; width = GTK_WIDGET(xtext)->allocation.width; gdk_draw_line(xtext->draw_buf, xtext->marker_gc, x, render_y, x + width, render_y); #if GTK_CHECK_VERSION(2,4,0) if (gtk_window_has_toplevel_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(xtext))))) #else if (GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(xtext)))->has_focus) #endif { xtext->buffer->marker_seen = TRUE; } } static void gtk_xtext_paint(GtkWidget *widget, GdkRectangle * area) { GtkXText *xtext = GTK_XTEXT(widget); textentry *ent_start, *ent_end; int x, y; #if defined(USE_XLIB) || defined(WIN32) if (xtext->transparent) { gdk_window_get_origin(widget->window, &x, &y); /* update transparency only if it moved */ if (xtext->last_win_x != x || xtext->last_win_y != y) { xtext->last_win_x = x; xtext->last_win_y = y; #if !defined(USE_SHM) && !defined(WIN32) if (xtext->shaded) { xtext->recycle = TRUE; gtk_xtext_load_trans(xtext); xtext->recycle = FALSE; } else #endif { gtk_xtext_free_trans(xtext); gtk_xtext_load_trans(xtext); } } } #endif if (area->x == 0 && area->y == 0 && area->height == widget->allocation.height && area->width == widget->allocation.width) { dontscroll(xtext->buffer); /* force scrolling off */ gtk_xtext_render_page(xtext); return; } ent_start = gtk_xtext_find_char(xtext, area->x, area->y, NULL, NULL); if (!ent_start) { xtext_draw_bg(xtext, area->x, area->y, area->width, area->height); goto xit; } ent_end = gtk_xtext_find_char(xtext, area->x + area->width, area->y + area->height, NULL, NULL); if (!ent_end) ent_end = xtext->buffer->text_last; /* can't set a clip here, because fgc/bgc are used to draw the DB too */ /* backend_set_clip (xtext, area);*/ xtext->clip_x = area->x; xtext->clip_x2 = area->x + area->width; xtext->clip_y = area->y; xtext->clip_y2 = area->y + area->height; /* y is the last pixel y location it rendered text at */ y = gtk_xtext_render_ents(xtext, ent_start, ent_end); if (y && y < widget->allocation.height && !ent_end->next) { GdkRectangle rect; rect.x = 0; rect.y = y; rect.width = widget->allocation.width; rect.height = widget->allocation.height - y; /* fill any space below the last line that also intersects with the exposure rectangle */ if (gdk_rectangle_intersect(area, &rect, &rect)) { xtext_draw_bg(xtext, rect.x, rect.y, rect.width, rect.height); } } /*backend_clear_clip (xtext); */ xtext->clip_x = 0; xtext->clip_x2 = 1000000; xtext->clip_y = 0; xtext->clip_y2 = 1000000; xit: x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (area->x <= x) gtk_xtext_draw_sep(xtext, -1); } static gboolean gtk_xtext_expose(GtkWidget *widget, GdkEventExpose * event) { gtk_xtext_paint(widget, &event->area); return FALSE; } /* render a selection that has extended or contracted upward */ static void gtk_xtext_selection_up(GtkXText * xtext, textentry * start, textentry * end, int start_offset) { /* render all the complete lines */ if (start->next == end) gtk_xtext_render_ents(xtext, end, NULL); else gtk_xtext_render_ents(xtext, start->next, end); /* now the incomplete upper line */ if (start == xtext->buffer->last_ent_start) xtext->jump_in_offset = xtext->buffer->last_offset_start; else xtext->jump_in_offset = start_offset; gtk_xtext_render_ents(xtext, start, NULL); xtext->jump_in_offset = 0; } /* render a selection that has extended or contracted downward */ static void gtk_xtext_selection_down(GtkXText * xtext, textentry * start, textentry * end, int end_offset) { /* render all the complete lines */ if (end->prev == start) gtk_xtext_render_ents(xtext, start, NULL); else gtk_xtext_render_ents(xtext, start, end->prev); /* now the incomplete bottom line */ if (end == xtext->buffer->last_ent_end) xtext->jump_out_offset = xtext->buffer->last_offset_end; else xtext->jump_out_offset = end_offset; gtk_xtext_render_ents(xtext, end, NULL); xtext->jump_out_offset = 0; } static void gtk_xtext_selection_render(GtkXText * xtext, textentry * start_ent, int start_offset, textentry * end_ent, int end_offset) { textentry *ent; int start, end; xtext->skip_border_fills = TRUE; xtext->skip_stamp = TRUE; /* force an optimized render if there was no previous selection */ if (xtext->buffer->last_ent_start == NULL && start_ent == end_ent) { xtext->buffer->last_offset_start = start_offset; xtext->buffer->last_offset_end = end_offset; goto lamejump; } /* mark changed within 1 ent only? */ if (xtext->buffer->last_ent_start == start_ent && xtext->buffer->last_ent_end == end_ent) { /* when only 1 end of the selection is changed, we can really save on rendering */ if (xtext->buffer->last_offset_start == start_offset || xtext->buffer->last_offset_end == end_offset) { lamejump: ent = end_ent; /* figure out where to start and end the rendering */ if (end_offset > xtext->buffer->last_offset_end) { end = end_offset; start = xtext->buffer->last_offset_end; } else if (end_offset < xtext->buffer->last_offset_end) { end = xtext->buffer->last_offset_end; start = end_offset; } else if (start_offset < xtext->buffer->last_offset_start) { end = xtext->buffer->last_offset_start; start = start_offset; ent = start_ent; } else if (start_offset > xtext->buffer->last_offset_start) { end = start_offset; start = xtext->buffer->last_offset_start; ent = start_ent; } else { /* WORD selects end up here */ end = end_offset; start = start_offset; } } else { /* LINE selects end up here */ /* so which ent actually changed? */ ent = start_ent; if (xtext->buffer->last_offset_start == start_offset) ent = end_ent; end = MAX(xtext->buffer->last_offset_end, end_offset); start = MIN(xtext->buffer->last_offset_start, start_offset); } xtext->jump_out_offset = end; xtext->jump_in_offset = start; gtk_xtext_render_ents(xtext, ent, NULL); xtext->jump_out_offset = 0; xtext->jump_in_offset = 0; } /* marking downward? */ else if (xtext->buffer->last_ent_start == start_ent && xtext->buffer->last_offset_start == start_offset) { /* find the range that covers both old and new selection */ for (ent = start_ent; ent; ent = ent->next) { if (ent == xtext->buffer->last_ent_end) { gtk_xtext_selection_down(xtext, ent, end_ent, end_offset); /*gtk_xtext_render_ents (xtext, ent, end_ent); */ break; } if (ent == end_ent) { gtk_xtext_selection_down(xtext, ent, xtext->buffer->last_ent_end, end_offset); /*gtk_xtext_render_ents (xtext, ent, xtext->buffer->last_ent_end); */ break; } } } /* marking upward? */ else if (xtext->buffer->last_ent_end == end_ent && xtext->buffer->last_offset_end == end_offset) { for (ent = end_ent; ent; ent = ent->prev) { if (ent == start_ent) { gtk_xtext_selection_up(xtext, xtext->buffer->last_ent_start, ent, start_offset); /*gtk_xtext_render_ents (xtext, xtext->buffer->last_ent_start, ent); */ break; } if (ent == xtext->buffer->last_ent_start) { gtk_xtext_selection_up(xtext, start_ent, ent, start_offset); /*gtk_xtext_render_ents (xtext, start_ent, ent); */ break; } } } else { /* cross-over mark (stretched or shrunk at both ends) */ /* unrender the old mark */ gtk_xtext_render_ents(xtext, xtext->buffer->last_ent_start, xtext->buffer->last_ent_end); /* now render the new mark, but skip overlaps */ if (start_ent == xtext->buffer->last_ent_start) { /* if the new mark is a sub-set of the old, do nothing */ if (start_ent != end_ent) gtk_xtext_render_ents(xtext, start_ent->next, end_ent); } else if (end_ent == xtext->buffer->last_ent_end) { /* if the new mark is a sub-set of the old, do nothing */ if (start_ent != end_ent) gtk_xtext_render_ents(xtext, start_ent, end_ent->prev); } else gtk_xtext_render_ents(xtext, start_ent, end_ent); } xtext->buffer->last_ent_start = start_ent; xtext->buffer->last_ent_end = end_ent; xtext->buffer->last_offset_start = start_offset; xtext->buffer->last_offset_end = end_offset; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; } static void gtk_xtext_selection_draw(GtkXText * xtext, GdkEventMotion * event, gboolean render) { textentry *ent; textentry *ent_end; textentry *ent_start; int offset_start; int offset_end; int low_x; int low_y; int high_x; int high_y; int tmp; if (xtext->select_start_y > xtext->select_end_y) { low_x = xtext->select_end_x; low_y = xtext->select_end_y; high_x = xtext->select_start_x; high_y = xtext->select_start_y; } else { low_x = xtext->select_start_x; low_y = xtext->select_start_y; high_x = xtext->select_end_x; high_y = xtext->select_end_y; } ent_start = gtk_xtext_find_char(xtext, low_x, low_y, &offset_start, &tmp); if (!ent_start) { if (xtext->adj->value != xtext->buffer->old_value) gtk_xtext_render_page(xtext); return; } ent_end = gtk_xtext_find_char(xtext, high_x, high_y, &offset_end, &tmp); if (!ent_end) { ent_end = xtext->buffer->text_last; if (!ent_end) { if (xtext->adj->value != xtext->buffer->old_value) gtk_xtext_render_page(xtext); return; } offset_end = ent_end->str_len; } /* marking less than a complete line? */ /* make sure "start" is smaller than "end" (swap them if need be) */ if (ent_start == ent_end && offset_start > offset_end) { tmp = offset_start; offset_start = offset_end; offset_end = tmp; } /* has the selection changed? Dont render unless necessary */ if (xtext->buffer->last_ent_start == ent_start && xtext->buffer->last_ent_end == ent_end && xtext->buffer->last_offset_start == offset_start && xtext->buffer->last_offset_end == offset_end) return; /* set all the old mark_ fields to -1 */ gtk_xtext_selection_clear(xtext->buffer); ent_start->mark_start = offset_start; ent_start->mark_end = offset_end; if (ent_start != ent_end) { ent_start->mark_end = ent_start->str_len; if (offset_end != 0) { ent_end->mark_start = 0; ent_end->mark_end = offset_end; } /* set all the mark_ fields of the ents within the selection */ for (ent = ent_start->next; (ent && ent != ent_end); ent = ent->next) { ent->mark_start = 0; ent->mark_end = ent->str_len; } } if (render) gtk_xtext_selection_render(xtext, ent_start, offset_start, ent_end, offset_end); } static gint gtk_xtext_scrolldown_timeout(GtkXText * xtext) { int p_y, win_height; gdk_window_get_pointer(GTK_WIDGET(xtext)->window, 0, &p_y, 0); gdk_drawable_get_size(GTK_WIDGET(xtext)->window, 0, &win_height); if (p_y > win_height && xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size)) { xtext->adj->value++; gtk_adjustment_changed(xtext->adj); gtk_xtext_render_page(xtext); return 1; } xtext->scroll_tag = 0; return 0; } static gint gtk_xtext_scrollup_timeout(GtkXText * xtext) { int p_y; gdk_window_get_pointer(GTK_WIDGET(xtext)->window, 0, &p_y, 0); if (p_y < 0 && xtext->adj->value > 0.0) { xtext->adj->value--; gtk_adjustment_changed(xtext->adj); gtk_xtext_render_page(xtext); return 1; } xtext->scroll_tag = 0; return 0; } static void gtk_xtext_selection_update(GtkXText * xtext, GdkEventMotion * event, int p_y, gboolean render) { int win_height; int moved; gdk_drawable_get_size(GTK_WIDGET(xtext)->window, 0, &win_height); /* selecting past top of window, scroll up! */ if (p_y < 0 && xtext->adj->value >= 0) { if (!xtext->scroll_tag) xtext->scroll_tag = g_timeout_add(100, (GSourceFunc) gtk_xtext_scrollup_timeout, xtext); return; } /* selecting past bottom of window, scroll down! */ if (p_y > win_height && xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size)) { if (!xtext->scroll_tag) xtext->scroll_tag = g_timeout_add(100, (GSourceFunc) gtk_xtext_scrolldown_timeout, xtext); return; } moved = (int)xtext->adj->value - xtext->select_start_adj; xtext->select_start_y -= (moved * xtext->fontsize); xtext->select_start_adj = xtext->adj->value; gtk_xtext_selection_draw(xtext, event, render); } static char *gtk_xtext_get_word(GtkXText * xtext, int x, int y, textentry ** ret_ent, int *ret_off, int *ret_len) { textentry *ent; int offset; unsigned char *str; unsigned char *word; int len; int out_of_bounds = 0; ent = gtk_xtext_find_char(xtext, x, y, &offset, &out_of_bounds); if (!ent) return NULL; if (out_of_bounds) return NULL; if (offset == ent->str_len) return NULL; if (offset < 1) return NULL; /*offset--; *//* FIXME: not all chars are 1 byte */ str = ent->str + offset; while (!is_del(*str) && str != ent->str) str--; word = str + 1; len = 0; str = word; while (!is_del(*str) && len != ent->str_len) { str++; len++; } if (len > 0 && word[len - 1] == '.') { len--; str--; } if (ret_ent) *ret_ent = ent; if (ret_off) *ret_off = word - ent->str; if (ret_len) *ret_len = str - word; return gtk_xtext_strip_color(word, len, xtext->scratch_buffer, NULL); } #ifdef MOTION_MONITOR static void gtk_xtext_unrender_hilight(GtkXText * xtext) { xtext->render_hilights_only = TRUE; xtext->skip_border_fills = TRUE; xtext->skip_stamp = TRUE; xtext->un_hilight = TRUE; gtk_xtext_render_ents(xtext, xtext->hilight_ent, NULL); xtext->render_hilights_only = FALSE; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; xtext->un_hilight = FALSE; } static gboolean gtk_xtext_leave_notify(GtkWidget *widget, GdkEventCrossing * event) { GtkXText *xtext = GTK_XTEXT(widget); if (xtext->cursor_hand) { gtk_xtext_unrender_hilight(xtext); xtext->hilight_start = -1; xtext->hilight_end = -1; xtext->cursor_hand = FALSE; gdk_window_set_cursor(widget->window, 0); xtext->hilight_ent = NULL; } if (xtext->cursor_resize) { gtk_xtext_unrender_hilight(xtext); xtext->hilight_start = -1; xtext->hilight_end = -1; xtext->cursor_resize = FALSE; gdk_window_set_cursor(widget->window, 0); xtext->hilight_ent = NULL; } return FALSE; } #endif /* check if we should mark time stamps, and if a redraw is needed */ static gboolean gtk_xtext_check_mark_stamp(GtkXText * xtext, GdkModifierType mask) { gboolean redraw = FALSE; if ((mask & GDK_SHIFT_MASK)) { if (!xtext->mark_stamp) { redraw = TRUE; /* must redraw all */ xtext->mark_stamp = TRUE; } } else { if (xtext->mark_stamp) { redraw = TRUE; /* must redraw all */ xtext->mark_stamp = FALSE; } } return redraw; } static gboolean gtk_xtext_motion_notify(GtkWidget *widget, GdkEventMotion * event) { GtkXText *xtext = GTK_XTEXT(widget); GdkModifierType mask; int redraw, tmp, x, y, offset, len, line_x; unsigned char *word; textentry *word_ent; gdk_window_get_pointer(widget->window, &x, &y, &mask); if (xtext->moving_separator) { if (x < (3 * widget->allocation.width) / 5 && x > 15) { tmp = xtext->buffer->indent; xtext->buffer->indent = x; gtk_xtext_fix_indent(xtext->buffer); if (tmp != xtext->buffer->indent) { gtk_xtext_recalc_widths(xtext->buffer, FALSE); if (xtext->buffer->scrollbar_down) gtk_adjustment_set_value(xtext->adj, xtext->adj->upper - xtext->adj->page_size); if (!xtext->io_tag) xtext->io_tag = g_timeout_add(REFRESH_TIMEOUT, (GSourceFunc) gtk_xtext_adjustment_timeout, xtext); } } return FALSE; } if (xtext->button_down) { redraw = gtk_xtext_check_mark_stamp(xtext, mask); gtk_grab_add(widget); /*gdk_pointer_grab (widget->window, TRUE, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK, NULL, NULL, 0); */ xtext->select_end_x = x; xtext->select_end_y = y; gtk_xtext_selection_update(xtext, event, y, !redraw); xtext->hilighting = TRUE; /* user has pressed or released SHIFT, must redraw entire selection */ if (redraw) { xtext->force_stamp = TRUE; gtk_xtext_render_ents(xtext, xtext->buffer->last_ent_start, xtext->buffer->last_ent_end); xtext->force_stamp = FALSE; } return FALSE; } #ifdef MOTION_MONITOR if (xtext->separator && xtext->buffer->indent) { line_x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (line_x == x || line_x == x + 1 || line_x == x - 1) { if (!xtext->cursor_resize) { gdk_window_set_cursor(GTK_WIDGET(xtext)->window, xtext->resize_cursor); xtext->cursor_resize = TRUE; } return FALSE; } } if (xtext->urlcheck_function == NULL) return FALSE; word = gtk_xtext_get_word(xtext, x, y, &word_ent, &offset, &len); if (word) { if (xtext->urlcheck_function(GTK_WIDGET(xtext), word, len) > 0) { if (!xtext->cursor_hand || xtext->hilight_ent != word_ent || xtext->hilight_start != offset || xtext->hilight_end != offset + len) { if (!xtext->cursor_hand) { gdk_window_set_cursor(GTK_WIDGET(xtext)->window, xtext->hand_cursor); xtext->cursor_hand = TRUE; } /* un-render the old hilight */ if (xtext->hilight_ent) gtk_xtext_unrender_hilight(xtext); xtext->hilight_ent = word_ent; xtext->hilight_start = offset; xtext->hilight_end = offset + len; xtext->skip_border_fills = TRUE; xtext->render_hilights_only = TRUE; xtext->skip_stamp = TRUE; gtk_xtext_render_ents(xtext, word_ent, NULL); xtext->skip_border_fills = FALSE; xtext->render_hilights_only = FALSE; xtext->skip_stamp = FALSE; } return FALSE; } } gtk_xtext_leave_notify(widget, NULL); #endif return FALSE; } static void gtk_xtext_set_clip_owner(GtkWidget *xtext, GdkEventButton * event) { char *str; int len; if (GTK_XTEXT(xtext)->selection_buffer && GTK_XTEXT(xtext)->selection_buffer != GTK_XTEXT(xtext)->buffer) gtk_xtext_selection_clear(GTK_XTEXT(xtext)->selection_buffer); GTK_XTEXT(xtext)->selection_buffer = GTK_XTEXT(xtext)->buffer; if ((str = gtk_xtext_selection_get_text(GTK_XTEXT(xtext), &len))) { #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), str, len); #else gtk_clipboard_set_text(gtk_widget_get_clipboard(xtext, GDK_SELECTION_CLIPBOARD), str, len); #endif free(str); } gtk_selection_owner_set(xtext, GDK_SELECTION_PRIMARY, event->time); } static void gtk_xtext_unselect(GtkXText * xtext) { xtext_buffer *buf = xtext->buffer; xtext->skip_border_fills = TRUE; xtext->skip_stamp = TRUE; xtext->jump_in_offset = buf->last_ent_start->mark_start; /* just a single ent was marked? */ if (buf->last_ent_start == buf->last_ent_end) { xtext->jump_out_offset = buf->last_ent_start->mark_end; buf->last_ent_end = NULL; } gtk_xtext_selection_clear(xtext->buffer); /* FIXME: use jump_out on multi-line selects too! */ gtk_xtext_render_ents(xtext, buf->last_ent_start, buf->last_ent_end); xtext->jump_in_offset = 0; xtext->jump_out_offset = 0; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; xtext->buffer->last_ent_start = NULL; xtext->buffer->last_ent_end = NULL; } static gboolean gtk_xtext_button_release(GtkWidget *widget, GdkEventButton * event) { GtkXText *xtext = GTK_XTEXT(widget); unsigned char *word; int old; if (xtext->moving_separator) { xtext->moving_separator = FALSE; old = xtext->buffer->indent; if (event->x < (4 * widget->allocation.width) / 5 && event->x > 15) xtext->buffer->indent = event->x; gtk_xtext_fix_indent(xtext->buffer); if (xtext->buffer->indent != old) { gtk_xtext_recalc_widths(xtext->buffer, FALSE); gtk_xtext_adjustment_set(xtext->buffer, TRUE); gtk_xtext_render_page(xtext); } else gtk_xtext_draw_sep(xtext, -1); return FALSE; } if (xtext->word_or_line_select) { xtext->word_or_line_select = FALSE; xtext->button_down = FALSE; return FALSE; } if (event->button == 1) { xtext->button_down = FALSE; gtk_grab_remove(widget); /*gdk_pointer_ungrab (0); */ if (xtext->buffer->last_ent_start) gtk_xtext_set_clip_owner(GTK_WIDGET(xtext), event); if (xtext->select_start_x == event->x && xtext->select_start_y == event->y && xtext->buffer->last_ent_start) { gtk_xtext_unselect(xtext); xtext->mark_stamp = FALSE; return FALSE; } if (!xtext->hilighting) { word = gtk_xtext_get_word(xtext, event->x, event->y, 0, 0, 0); g_signal_emit(G_OBJECT(xtext), xtext_signals[WORD_CLICK], 0, word ? word : NULL, event); } else { xtext->hilighting = FALSE; } } return FALSE; } static gboolean gtk_xtext_button_press(GtkWidget *widget, GdkEventButton * event) { GtkXText *xtext = GTK_XTEXT(widget); GdkModifierType mask; textentry *ent; unsigned char *word; int line_x, x, y, offset, len; gdk_window_get_pointer(widget->window, &x, &y, &mask); if (event->button == 3 || event->button == 2) { /* right/middle click */ word = gtk_xtext_get_word(xtext, x, y, 0, 0, 0); if (word) { g_signal_emit(G_OBJECT(xtext), xtext_signals[WORD_CLICK], 0, word, event); } else g_signal_emit(G_OBJECT(xtext), xtext_signals[WORD_CLICK], 0, "", event); return FALSE; } if (event->button != 1) /* we only want left button */ return FALSE; if (event->type == GDK_2BUTTON_PRESS) { /* WORD select */ gtk_xtext_check_mark_stamp(xtext, mask); if (gtk_xtext_get_word(xtext, x, y, &ent, &offset, &len)) { if (len == 0) return FALSE; gtk_xtext_selection_clear(xtext->buffer); ent->mark_start = offset; ent->mark_end = offset + len; gtk_xtext_selection_render(xtext, ent, offset, ent, offset + len); xtext->word_or_line_select = TRUE; gtk_xtext_set_clip_owner(GTK_WIDGET(xtext), event); } return FALSE; } if (event->type == GDK_3BUTTON_PRESS) { /* LINE select */ gtk_xtext_check_mark_stamp(xtext, mask); if (gtk_xtext_get_word(xtext, x, y, &ent, 0, 0)) { gtk_xtext_selection_clear(xtext->buffer); ent->mark_start = 0; ent->mark_end = ent->str_len; gtk_xtext_selection_render(xtext, ent, 0, ent, ent->str_len); xtext->word_or_line_select = TRUE; gtk_xtext_set_clip_owner(GTK_WIDGET(xtext), event); } return FALSE; } /* check if it was a separator-bar click */ if (xtext->separator && xtext->buffer->indent) { line_x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (line_x == x || line_x == x + 1 || line_x == x - 1) { xtext->moving_separator = TRUE; /* draw the separator line */ gtk_xtext_draw_sep(xtext, -1); return FALSE; } } xtext->button_down = TRUE; xtext->select_start_x = x; xtext->select_start_y = y; xtext->select_start_adj = xtext->adj->value; return FALSE; } /* another program has claimed the selection */ static gboolean gtk_xtext_selection_kill(GtkXText * xtext, GdkEventSelection * event) { if (xtext->buffer->last_ent_start) gtk_xtext_unselect(xtext); return TRUE; } static char *gtk_xtext_selection_get_text(GtkXText * xtext, int *len_ret) { textentry *ent; char *txt; char *pos; int len; int first = TRUE; xtext_buffer *buf; buf = xtext->selection_buffer; if (!buf) return NULL; /* first find out how much we need to malloc ... */ len = 0; for (ent = buf->last_ent_start; ent; ent = ent->next) { if (ent->mark_start != -1) { /* include timestamp? */ if (ent->mark_start == 0 && xtext->mark_stamp) { int stamp_size = strlen(timestamp_time("%H:%M:%S", ent->fstr->ts)); len += stamp_size; } if (ent->mark_end - ent->mark_start > 0) len += (ent->mark_end - ent->mark_start) + 1; else len++; } if (ent == buf->last_ent_end) break; } if (len < 1) return NULL; /* now allocate mem and copy buffer */ pos = txt = xmalloc(len); for (ent = buf->last_ent_start; ent; ent = ent->next) { if (ent->mark_start != -1) { if (!first) { *pos = '\n'; pos++; } first = FALSE; if (ent->mark_end - ent->mark_start > 0) { /* include timestamp? */ if (ent->mark_start == 0 && xtext->mark_stamp) { const char *time_str = timestamp_time("%H:%M:%S", ent->fstr->ts); int stamp_size = strlen(time_str); memcpy(pos, time_str, stamp_size); pos += stamp_size; } memcpy(pos, ent->str + ent->mark_start, ent->mark_end - ent->mark_start); pos += ent->mark_end - ent->mark_start; } } if (ent == buf->last_ent_end) break; } *pos = 0; *len_ret = strlen(txt); return txt; } /* another program is asking for our selection */ static void gtk_xtext_selection_get(GtkWidget *widget, GtkSelectionData * selection_data_ptr, guint info, guint time) { GtkXText *xtext = GTK_XTEXT(widget); char *stripped; guchar *new_text; int len; gsize glen; if (!(stripped = gtk_xtext_selection_get_text(xtext, &len))) return; switch (info) { case TARGET_UTF8_STRING: /* it's already in utf8 */ gtk_selection_data_set_text(selection_data_ptr, stripped, len); break; case TARGET_TEXT: case TARGET_COMPOUND_TEXT: { GdkAtom encoding; gint format; gint new_length; #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) gdk_string_to_compound_text( #else gdk_string_to_compound_text_for_display(gdk_drawable_get_display (widget->window), #endif stripped, &encoding, &format, &new_text, &new_length); gtk_selection_data_set(selection_data_ptr, encoding, format, new_text, new_length); gdk_free_compound_text(new_text); } break; default: new_text = g_locale_from_utf8(stripped, len, NULL, &glen, NULL); gtk_selection_data_set(selection_data_ptr, GDK_SELECTION_TYPE_STRING, 8, new_text, glen); g_free(new_text); } free(stripped); } static gboolean gtk_xtext_scroll(GtkWidget *widget, GdkEventScroll * event) { GtkXText *xtext = GTK_XTEXT(widget); gfloat new_value; if (event->direction == GDK_SCROLL_UP) { /* mouse wheel pageUp */ new_value = xtext->adj->value - (xtext->adj->page_increment / 10); if (new_value < xtext->adj->lower) new_value = xtext->adj->lower; gtk_adjustment_set_value(xtext->adj, new_value); } else if (event->direction == GDK_SCROLL_DOWN) { /* mouse wheel pageDn */ new_value = xtext->adj->value + (xtext->adj->page_increment / 10); if (new_value > (xtext->adj->upper - xtext->adj->page_size)) new_value = xtext->adj->upper - xtext->adj->page_size; gtk_adjustment_set_value(xtext->adj, new_value); } return FALSE; } static void gtk_xtext_class_init(GtkXTextClass * class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkXTextClass *xtext_class; object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; xtext_class = (GtkXTextClass *) class; parent_class = gtk_type_class(gtk_widget_get_type()); xtext_signals[WORD_CLICK] = g_signal_new("word_click", G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(GtkXTextClass, word_click), NULL, NULL, gtk_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); object_class->destroy = gtk_xtext_destroy; widget_class->realize = gtk_xtext_realize; widget_class->unrealize = gtk_xtext_unrealize; widget_class->size_request = gtk_xtext_size_request; widget_class->size_allocate = gtk_xtext_size_allocate; widget_class->button_press_event = gtk_xtext_button_press; widget_class->button_release_event = gtk_xtext_button_release; widget_class->motion_notify_event = gtk_xtext_motion_notify; widget_class->selection_clear_event = (void *)gtk_xtext_selection_kill; widget_class->selection_get = gtk_xtext_selection_get; widget_class->expose_event = gtk_xtext_expose; widget_class->scroll_event = gtk_xtext_scroll; #ifdef MOTION_MONITOR widget_class->leave_notify_event = gtk_xtext_leave_notify; #endif xtext_class->word_click = NULL; } GtkType gtk_xtext_get_type(void) { static GtkType xtext_type = 0; if (!xtext_type) { static const GTypeInfo xtext_info = { sizeof(GtkXTextClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) gtk_xtext_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(GtkXText), 0, /* n_preallocs */ (GInstanceInitFunc) gtk_xtext_init, }; xtext_type = g_type_register_static(GTK_TYPE_WIDGET, "GtkXText", &xtext_info, 0); } return xtext_type; } /* copy text to outbuf, [len bytes], terminate with \0 * set *mb_ret to TRUE, if there're chars with ANSI code >= 128 */ static unsigned char *gtk_xtext_strip_color(unsigned char *text, int len, unsigned char *outbuf, int *mb_ret) { int i = 0; int mb = FALSE; for (i = 0; i < len; i++) { if (text[i] >= 128) mb = TRUE; outbuf[i] = *text; } outbuf[len] = 0; if (mb_ret != NULL) *mb_ret = mb; return outbuf; } /* gives width of a string */ static int gtk_xtext_text_width(GtkXText * xtext, unsigned char *text, int len, int *mb_ret) { unsigned char *new_buf; int mb; new_buf = gtk_xtext_strip_color(text, len, xtext->scratch_buffer, &mb); if (mb_ret) *mb_ret = mb; return backend_get_text_width(xtext, new_buf, len, mb); } /* actually draw text to screen (one run with the same color/attribs) */ static int gtk_xtext_render_flush(GtkXText * xtext, int x, int y, unsigned char *str, int len, GdkGC * gc, int is_mb) { int str_width, dofill; GdkDrawable *pix = NULL; int dest_x, dest_y; if (xtext->dont_render || len < 1) return 0; str_width = backend_get_text_width(xtext, str, len, is_mb); if (xtext->dont_render2) return str_width; /* roll-your-own clipping (avoiding XftDrawString is always good!) */ if (x > xtext->clip_x2 || x + str_width < xtext->clip_x) return str_width; if (y - xtext->font->ascent > xtext->clip_y2 || (y - xtext->font->ascent) + xtext->fontsize < xtext->clip_y) return str_width; if (xtext->render_hilights_only) { if (!xtext->in_hilight) /* is it a hilight prefix? */ return str_width; #ifndef COLOR_HILIGHT if (!xtext->un_hilight) /* doing a hilight? no need to draw the text */ goto dounder; #endif } #ifdef USE_DB pix = gdk_pixmap_new(xtext->draw_buf, str_width, xtext->fontsize, xtext->depth); if (pix) { #ifdef USE_XFT XftDrawChange(xtext->xftdraw, GDK_WINDOW_XWINDOW(pix)); #endif dest_x = x; dest_y = y - xtext->font->ascent; gdk_gc_set_ts_origin(xtext->bgc, xtext->ts_x - x, xtext->ts_y - dest_y); x = 0; y = xtext->font->ascent; xtext->draw_buf = pix; } #endif dofill = TRUE; /* backcolor is always handled by XDrawImageString */ if (!xtext->backcolor && xtext->pixmap) { /* draw the background pixmap behind the text - CAUSES FLICKER HERE!! */ xtext_draw_bg(xtext, x, y - xtext->font->ascent, str_width, xtext->fontsize); dofill = FALSE; /* already drawn the background */ } backend_draw_text(xtext, dofill, gc, x, y, str, len, str_width, is_mb); #ifdef USE_DB if (pix) { GdkRectangle clip; GdkRectangle dest; gdk_gc_set_ts_origin(xtext->bgc, xtext->ts_x, xtext->ts_y); xtext->draw_buf = GTK_WIDGET(xtext)->window; #ifdef USE_XFT XftDrawChange(xtext->xftdraw, GDK_WINDOW_XWINDOW(xtext->draw_buf)); #endif clip.x = xtext->clip_x; clip.y = xtext->clip_y; clip.width = xtext->clip_x2 - xtext->clip_x; clip.height = xtext->clip_y2 - xtext->clip_y; dest.x = dest_x; dest.y = dest_y; dest.width = str_width; dest.height = xtext->fontsize; if (gdk_rectangle_intersect(&clip, &dest, &dest)) /* dump the DB to window, but only within the clip_x/x2/y/y2 */ gdk_draw_drawable(xtext->draw_buf, xtext->bgc, pix, dest.x - dest_x, dest.y - dest_y, dest.x, dest.y, dest.width, dest.height); g_object_unref(pix); } #endif if (xtext->underline) { #ifdef USE_XFT GdkColor col; #endif #ifndef COLOR_HILIGHT dounder: #endif #ifdef USE_XFT col.pixel = xtext->xft_fg->pixel; gdk_gc_set_foreground(gc, &col); #endif if (pix) y = dest_y + xtext->font->ascent + 1; else { y++; dest_x = x; } /* draw directly to window, it's out of the range of our DB */ gdk_draw_line(xtext->draw_buf, gc, dest_x, y, dest_x + str_width - 1, y); } return str_width; } static void gtk_xtext_reset(GtkXText * xtext, int mark, int attribs) { if (attribs) { xtext->underline = FALSE; xtext->bold = FALSE; xtext->italics = FALSE; } if (!mark) { xtext->backcolor = FALSE; if (xtext->col_fore != XTEXT_FG) xtext_set_fg(xtext, xtext->fgc, XTEXT_FG); if (xtext->col_back != XTEXT_BG) xtext_set_bg(xtext, xtext->fgc, XTEXT_BG); } xtext->col_fore = XTEXT_FG; xtext->col_back = XTEXT_BG; xtext->nc = 0; } /* render a single line, which WONT wrap, and parse fstring_t attr */ static int gtk_xtext_render_str(GtkXText * xtext, int y, textentry * ent, unsigned char *str, unsigned char *attr, int len, int win_width, int indent, int line, int left_only, int *x_size_ret) { GdkGC *gc; int i = 0, x = indent, j = 0; unsigned char *pstr = str; int offset; int mark = FALSE; int ret = 1; unsigned char last_attr = 128; xtext->in_hilight = FALSE; offset = str - ent->str; if (line < 255 && line >= 0) xtext->buffer->grid_offset[line] = offset; gc = xtext->fgc; /* our foreground GC */ if (ent->mark_start != -1 && ent->mark_start <= i + offset && ent->mark_end > i + offset) { xtext_set_bg(xtext, gc, XTEXT_MARK_BG); xtext_set_fg(xtext, gc, XTEXT_MARK_FG); xtext->backcolor = TRUE; mark = TRUE; } #ifdef MOTION_MONITOR if (xtext->hilight_ent == ent && xtext->hilight_start <= i + offset && xtext->hilight_end > i + offset) { if (!xtext->un_hilight) { #ifdef COLOR_HILIGHT xtext_set_bg(xtext, gc, 2); #else xtext->underline = TRUE; #endif } xtext->in_hilight = TRUE; } #endif if (!xtext->skip_border_fills && !xtext->dont_render) { /* draw background to the left of the text */ if (str == ent->str && indent > MARGIN && xtext->buffer->time_stamp) { /* don't overwrite the timestamp */ if (indent > xtext->stamp_width) { xtext_draw_bg(xtext, xtext->stamp_width, y - xtext->font->ascent, indent - xtext->stamp_width, xtext->fontsize); } } else { /* fill the indent area with background gc */ if (indent >= xtext->clip_x) { xtext_draw_bg(xtext, 0, y - xtext->font->ascent, MIN(indent, xtext->clip_x2), xtext->fontsize); } } } if (xtext->jump_in_offset > 0 && offset < xtext->jump_in_offset) xtext->dont_render2 = TRUE; while (i < len) { #ifdef MOTION_MONITOR if (xtext->hilight_ent == ent && xtext->hilight_start == (i + offset)) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; if (!xtext->un_hilight) { #ifdef COLOR_HILIGHT xtext_set_bg(xtext, gc, 2); #else xtext->underline = TRUE; #endif } xtext->in_hilight = TRUE; } #endif if (attr && last_attr != attr[i]) { int isbold; last_attr = attr[i]; if (i) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; } gtk_xtext_reset(xtext, mark, !xtext->in_hilight); isbold = ((last_attr & 64) != 0); #warning "Verify, ekg2->ekg fstring_t" /* xtext->bold = (isbold); */ /* more follow */ /* DEBUG_RENDER("[B: %d] ", isbold); DEBUG_RENDER("[Bl: %d] ", last_attr & 256); DEBUG_RENDER("[U: %d] ", last_attr & 512); DEBUG_RENDER("[R: %d] ", last_attr & 1024); */ if (!(last_attr & 128)) { if (!mark) { xtext_set_fg(xtext, gc, ((last_attr & 7) + 8*isbold)); /* xtext_set_bg(xtext, gc, ((last_attr >> 3) & 7)); */ } xtext->col_fore = ((last_attr & 7) + 8*isbold); /* xtext->col_back = ((last_attr >> 3) & 7); */ } else { if (isbold) { if (!mark) xtext_set_fg(xtext, gc, 7+8); xtext->col_fore = 7+8; } } } if (str[i] != '\n') { int tmp = charlen(str + i); /* invalid utf8 safe guard */ if (tmp + i > len) tmp = len - i; j += tmp; /* move to the next utf8 char */ } i += charlen(str + i); /* move to the next utf8 char */ /* invalid utf8 safe guard */ if (i > len) i = len; /* Separate the left part, the space and the right part into separate runs, and reset bidi state inbetween. Perform this only on the first line of the message. */ if (offset == 0) { /* we've reached the end of the left part? */ if ((pstr - str) + j == ent->left_len) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; } else if ((pstr - str) + j == ent->left_len + 1) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; } } /* have we been told to stop rendering at this point? */ if (xtext->jump_out_offset > 0 && xtext->jump_out_offset <= (i + offset)) { gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); ret = 0; /* skip the rest of the lines, we're done. */ j = 0; break; } if (xtext->jump_in_offset > 0 && xtext->jump_in_offset == (i + offset)) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; xtext->dont_render2 = FALSE; } #ifdef MOTION_MONITOR if (xtext->hilight_ent == ent && xtext->hilight_end == (i + offset)) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; #ifdef COLOR_HILIGHT if (mark) { xtext_set_bg(xtext, gc, XTEXT_MARK_BG); xtext->backcolor = TRUE; } else { xtext_set_bg(xtext, gc, xtext->col_back); if (xtext->col_back != XTEXT_BG) xtext->backcolor = TRUE; else xtext->backcolor = FALSE; } #else xtext->underline = FALSE; #endif xtext->in_hilight = FALSE; if (xtext->render_hilights_only) { /* stop drawing this ent */ ret = 0; break; } } #endif if (!mark && ent->mark_start == (i + offset)) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; xtext_set_bg(xtext, gc, XTEXT_MARK_BG); xtext_set_fg(xtext, gc, XTEXT_MARK_FG); xtext->backcolor = TRUE; mark = TRUE; } if (mark && ent->mark_end == (i + offset)) { x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); pstr += j; j = 0; xtext_set_bg(xtext, gc, xtext->col_back); xtext_set_fg(xtext, gc, xtext->col_fore); if (xtext->col_back != XTEXT_BG) xtext->backcolor = TRUE; else xtext->backcolor = FALSE; mark = FALSE; } } if (j) x += gtk_xtext_render_flush(xtext, x, y, pstr, j, gc, ent->mb); if (mark) { xtext_set_bg(xtext, gc, xtext->col_back); xtext_set_fg(xtext, gc, xtext->col_fore); if (xtext->col_back != XTEXT_BG) xtext->backcolor = TRUE; else xtext->backcolor = FALSE; } /* draw background to the right of the text */ if (!left_only && !xtext->dont_render) { /* draw separator now so it doesn't appear to flicker */ gtk_xtext_draw_sep(xtext, y - xtext->font->ascent); if (!xtext->skip_border_fills && xtext->clip_x2 >= x) { int xx = MAX(x, xtext->clip_x); xtext_draw_bg(xtext, xx, /* x */ y - xtext->font->ascent, /* y */ MIN(xtext->clip_x2 - xx, (win_width + MARGIN) - xx), /* width */ xtext->fontsize); /* height */ } } xtext->dont_render2 = FALSE; /* return how much we drew in the x direction */ if (x_size_ret) *x_size_ret = x - indent; return ret; } #ifdef USE_XLIB /* get the desktop/root window */ static Window desktop_window = None; static Window get_desktop_window(Display * xdisplay, Window the_window) { Atom prop, type; int format; unsigned long length, after; unsigned char *data; unsigned int nchildren; Window w, root, *children, parent; prop = XInternAtom(xdisplay, "_XROOTPMAP_ID", True); if (prop == None) { prop = XInternAtom(xdisplay, "_XROOTCOLOR_PIXEL", True); if (prop == None) return None; } for (w = the_window; w; w = parent) { if ((XQueryTree(xdisplay, w, &root, &parent, &children, &nchildren)) == False) return None; if (nchildren) XFree(children); XGetWindowProperty(xdisplay, w, prop, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data); if (data) XFree(data); if (type != None) return (desktop_window = w); } return (desktop_window = None); } /* find the root window (backdrop) Pixmap */ static Pixmap get_pixmap_prop(Display * xdisplay, Window the_window) { Atom type; int format; unsigned long length, after; unsigned char *data; Pixmap pix = None; static Atom prop = None; if (desktop_window == None) desktop_window = get_desktop_window(xdisplay, the_window); if (desktop_window == None) desktop_window = DefaultRootWindow(xdisplay); if (prop == None) prop = XInternAtom(xdisplay, "_XROOTPMAP_ID", True); if (prop == None) return None; XGetWindowProperty(xdisplay, desktop_window, prop, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data); if (data) { if (type == XA_PIXMAP) pix = *((Pixmap *) data); XFree(data); } return pix; } /* slow generic routine, for the depths/bpp we don't know about */ static void shade_ximage_generic(GdkVisual * visual, XImage * ximg, int bpl, int w, int h, int rm, int gm, int bm, int bg) { int x, y; int bgr = (256 - rm) * (bg & visual->red_mask); int bgg = (256 - gm) * (bg & visual->green_mask); int bgb = (256 - bm) * (bg & visual->blue_mask); for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { unsigned long pixel = XGetPixel(ximg, x, y); int r, g, b; r = rm * (pixel & visual->red_mask) + bgr; g = gm * (pixel & visual->green_mask) + bgg; b = bm * (pixel & visual->blue_mask) + bgb; XPutPixel(ximg, x, y, ((r >> 8) & visual->red_mask) | ((g >> 8) & visual->green_mask) | ((b >> 8) & visual->blue_mask)); } } } #endif /* Fast shading routine. Based on code by Willem Monsuwe */ #define SHADE_IMAGE(bytes, type, rmask, gmask, bmask) \ unsigned char *ptr; \ int x, y; \ int bgr = (256 - rm) * (bg & rmask); \ int bgg = (256 - gm) * (bg & gmask); \ int bgb = (256 - bm) * (bg & bmask); \ ptr = (unsigned char *) data + (w * bytes); \ for (y = h; --y >= 0;) \ { \ for (x = -w; x < 0; x++) \ { \ int r, g, b; \ b = ((type *) ptr)[x]; \ r = rm * (b & rmask) + bgr; \ g = gm * (b & gmask) + bgg; \ b = bm * (b & bmask) + bgb; \ ((type *) ptr)[x] = ((r >> 8) & rmask) \ | ((g >> 8) & gmask) \ | ((b >> 8) & bmask); \ } \ ptr += bpl; \ } /* RGB 15 */ static void shade_ximage_15(void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) { SHADE_IMAGE(2, guint16, 0x7c00, 0x3e0, 0x1f); } /* RGB 16 */ static void shade_ximage_16(void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) { SHADE_IMAGE(2, guint16, 0xf800, 0x7e0, 0x1f); } /* RGB 24 */ static void shade_ximage_24(void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) { /* 24 has to be a special case, there's no guint24, or 24bit MOV :) */ unsigned char *ptr; int x, y; int bgr = (256 - rm) * ((bg & 0xff0000) >> 16); int bgg = (256 - gm) * ((bg & 0xff00) >> 8); int bgb = (256 - bm) * (bg & 0xff); ptr = (unsigned char *)data + (w * 3); for (y = h; --y >= 0;) { for (x = -(w * 3); x < 0; x += 3) { int r, g, b; #if (G_BYTE_ORDER == G_BIG_ENDIAN) r = (ptr[x + 0] * rm + bgr) >> 8; g = (ptr[x + 1] * gm + bgg) >> 8; b = (ptr[x + 2] * bm + bgb) >> 8; ptr[x + 0] = r; ptr[x + 1] = g; ptr[x + 2] = b; #else r = (ptr[x + 2] * rm + bgr) >> 8; g = (ptr[x + 1] * gm + bgg) >> 8; b = (ptr[x + 0] * bm + bgb) >> 8; ptr[x + 2] = r; ptr[x + 1] = g; ptr[x + 0] = b; #endif } ptr += bpl; } } /* RGB 32 */ static void shade_ximage_32(void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) { SHADE_IMAGE(4, guint32, 0xff0000, 0xff00, 0xff); } static void shade_image(GdkVisual * visual, void *data, int bpl, int bpp, int w, int h, int rm, int gm, int bm, int bg, int depth) { int bg_r, bg_g, bg_b; bg_r = bg & visual->red_mask; bg_g = bg & visual->green_mask; bg_b = bg & visual->blue_mask; #ifdef USE_MMX /* the MMX routines are about 50% faster at 16-bit. */ /* only use MMX routines with a pure black background */ if (bg_r == 0 && bg_g == 0 && bg_b == 0 && have_mmx()) { /* do a runtime check too! */ switch (depth) { case 15: shade_ximage_15_mmx(data, bpl, w, h, rm, gm, bm); break; case 16: shade_ximage_16_mmx(data, bpl, w, h, rm, gm, bm); break; case 24: if (bpp != 32) goto generic; case 32: shade_ximage_32_mmx(data, bpl, w, h, rm, gm, bm); break; default: goto generic; } } else { generic: #endif switch (depth) { case 15: shade_ximage_15(data, bpl, w, h, rm, gm, bm, bg); break; case 16: shade_ximage_16(data, bpl, w, h, rm, gm, bm, bg); break; case 24: if (bpp != 32) { shade_ximage_24(data, bpl, w, h, rm, gm, bm, bg); break; } case 32: shade_ximage_32(data, bpl, w, h, rm, gm, bm, bg); } #ifdef USE_MMX } #endif } #ifdef USE_XLIB #ifdef USE_SHM static XImage *get_shm_image(Display * xdisplay, XShmSegmentInfo * shminfo, int x, int y, int w, int h, int depth, Pixmap pix) { XImage *ximg; shminfo->shmid = -1; shminfo->shmaddr = (char *)-1; ximg = XShmCreateImage(xdisplay, 0, depth, ZPixmap, 0, shminfo, w, h); if (!ximg) return NULL; shminfo->shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT | 0600); if (shminfo->shmid == -1) { XDestroyImage(ximg); return NULL; } shminfo->readOnly = False; ximg->data = shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0); if (shminfo->shmaddr == ((char *)-1)) { shmctl(shminfo->shmid, IPC_RMID, 0); XDestroyImage(ximg); return NULL; } XShmAttach(xdisplay, shminfo); XSync(xdisplay, False); shmctl(shminfo->shmid, IPC_RMID, 0); XShmGetImage(xdisplay, pix, ximg, x, y, AllPlanes); return ximg; } static XImage *get_image(GtkXText * xtext, Display * xdisplay, XShmSegmentInfo * shminfo, int x, int y, int w, int h, int depth, Pixmap pix) { XImage *ximg; xtext->shm = 1; ximg = get_shm_image(xdisplay, shminfo, x, y, w, h, depth, pix); if (!ximg) { xtext->shm = 0; ximg = XGetImage(xdisplay, pix, x, y, w, h, -1, ZPixmap); } return ximg; } #endif static GdkPixmap *shade_pixmap(GtkXText * xtext, Pixmap p, int x, int y, int w, int h) { unsigned int dummy, width, height, depth; GdkPixmap *shaded_pix; Window root; Pixmap tmp; XImage *ximg; XGCValues gcv; GC tgc; Display *xdisplay = GDK_WINDOW_XDISPLAY(xtext->draw_buf); XGetGeometry(xdisplay, p, &root, &dummy, &dummy, &width, &height, &dummy, &depth); if (width < x + w || height < y + h || x < 0 || y < 0) { gcv.subwindow_mode = IncludeInferiors; gcv.graphics_exposures = False; tgc = XCreateGC(xdisplay, p, GCGraphicsExposures | GCSubwindowMode, &gcv); tmp = XCreatePixmap(xdisplay, p, w, h, depth); XSetTile(xdisplay, tgc, p); XSetFillStyle(xdisplay, tgc, FillTiled); XSetTSOrigin(xdisplay, tgc, -x, -y); XFillRectangle(xdisplay, tmp, tgc, 0, 0, w, h); XFreeGC(xdisplay, tgc); #ifdef USE_SHM ximg = get_image(xtext, xdisplay, &xtext->shminfo, 0, 0, w, h, depth, tmp); #else ximg = XGetImage(xdisplay, tmp, 0, 0, w, h, -1, ZPixmap); #endif XFreePixmap(xdisplay, tmp); } else { #ifdef USE_SHM ximg = get_image(xtext, xdisplay, &xtext->shminfo, x, y, w, h, depth, p); #else ximg = XGetImage(xdisplay, p, x, y, w, h, -1, ZPixmap); #endif } if (!ximg) return NULL; if (depth <= 14) { shade_ximage_generic(gdk_drawable_get_visual(GTK_WIDGET(xtext)->window), ximg, ximg->bytes_per_line, w, h, xtext->tint_red, xtext->tint_green, xtext->tint_blue, xtext->palette[XTEXT_BG]); } else { shade_image(gdk_drawable_get_visual(GTK_WIDGET(xtext)->window), ximg->data, ximg->bytes_per_line, ximg->bits_per_pixel, w, h, xtext->tint_red, xtext->tint_green, xtext->tint_blue, xtext->palette[XTEXT_BG], depth); } if (xtext->recycle) shaded_pix = xtext->pixmap; else { #ifdef USE_SHM if (xtext->shm) { #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) shaded_pix = gdk_pixmap_foreign_new(XShmCreatePixmap (xdisplay, p, ximg->data, &xtext->shminfo, w, h, depth)); #else shaded_pix = gdk_pixmap_foreign_new_for_display(gdk_drawable_get_display (xtext->draw_buf), XShmCreatePixmap(xdisplay, p, ximg->data, &xtext-> shminfo, w, h, depth)); #endif } else #endif { shaded_pix = gdk_pixmap_new(GTK_WIDGET(xtext)->window, w, h, depth); } } #ifdef USE_SHM if (!xtext->shm) #endif XPutImage(xdisplay, GDK_WINDOW_XWINDOW(shaded_pix), GDK_GC_XGC(xtext->fgc), ximg, 0, 0, 0, 0, w, h); XDestroyImage(ximg); return shaded_pix; } #endif /* !USE_XLIB */ /* free transparency xtext->pixmap */ #if defined(USE_XLIB) || defined(WIN32) static void gtk_xtext_free_trans(GtkXText * xtext) { if (xtext->pixmap) { #ifdef USE_SHM if (xtext->shm) { XFreePixmap(GDK_WINDOW_XDISPLAY(xtext->pixmap), GDK_WINDOW_XWINDOW(xtext->pixmap)); XShmDetach(GDK_WINDOW_XDISPLAY(xtext->draw_buf), &xtext->shminfo); shmdt(xtext->shminfo.shmaddr); } #endif g_object_unref(xtext->pixmap); xtext->pixmap = NULL; xtext->shm = 0; } } #endif /* grab pixmap from root window and set xtext->pixmap */ #if defined(USE_XLIB) || defined(WIN32) static void gtk_xtext_load_trans(GtkXText * xtext) { Pixmap rootpix; GtkWidget *widget = GTK_WIDGET(xtext); int x, y; rootpix = get_pixmap_prop(GDK_WINDOW_XDISPLAY(widget->window), GDK_WINDOW_XWINDOW(widget->window)); if (rootpix == None) { if (xtext->error_function) xtext->error_function(0); xtext->transparent = FALSE; return; } gdk_window_get_origin(widget->window, &x, &y); if (xtext->shaded) { int width, height; gdk_drawable_get_size(GTK_WIDGET(xtext)->window, &width, &height); xtext->pixmap = shade_pixmap(xtext, rootpix, x, y, width + 105, height); if (xtext->pixmap == NULL) { xtext->shaded = 0; goto noshade; } gdk_gc_set_tile(xtext->bgc, xtext->pixmap); gdk_gc_set_ts_origin(xtext->bgc, 0, 0); xtext->ts_x = xtext->ts_y = 0; } else { noshade: #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) xtext->pixmap = gdk_pixmap_foreign_new(rootpix); #else xtext->pixmap = gdk_pixmap_foreign_new_for_display(gdk_drawable_get_display (GTK_WIDGET(xtext)->window), rootpix); #endif gdk_gc_set_tile(xtext->bgc, xtext->pixmap); gdk_gc_set_ts_origin(xtext->bgc, -x, -y); xtext->ts_x = -x; xtext->ts_y = -y; } gdk_gc_set_fill(xtext->bgc, GDK_TILED); } #endif /* ! XLIB || WIN32 */ /* walk through str until this line doesn't fit anymore */ static int find_next_wrap(GtkXText * xtext, textentry * ent, unsigned char *str, int win_width, int indent) { unsigned char *last_space = str; unsigned char *orig_str = str; int str_width = indent; int mbl; int char_width; int ret; /* single liners */ if (win_width >= ent->str_width + ent->indent) return ent->str_len; /* it does happen! */ if (win_width < 1) { ret = ent->str_len - (str - ent->str); goto done; } while (1) { char_width = backend_get_char_width(xtext, str, &mbl); str_width += char_width; if (str_width > win_width) { if (xtext->wordwrap) { if (str - last_space > WORDWRAP_LIMIT) ret = str - orig_str; /* fall back to character wrap */ else { if (*last_space == ' ') last_space++; ret = last_space - orig_str; if (ret == 0) /* fall back to character wrap */ ret = str - orig_str; } goto done; } ret = str - orig_str; goto done; } /* keep a record of the last space, for wordwrapping */ if (is_del(*str)) last_space = str; /* progress to the next char */ str += mbl; if (str >= ent->str + ent->str_len) { ret = str - orig_str; goto done; } } done: /* must make progress */ if (ret < 1) ret = 1; return ret; } /* find the offset, in bytes, that wrap number 'line' starts at */ static int gtk_xtext_find_subline(GtkXText * xtext, textentry * ent, int line) { int win_width; unsigned char *str; int indent, str_pos, line_pos, len; if (ent->lines_taken < 2 || line < 1) return 0; /* we record the first 4 lines' wraps, so take a shortcut */ if (line <= RECORD_WRAPS) return ent->wrap_offset[line - 1]; gdk_drawable_get_size(GTK_WIDGET(xtext)->window, &win_width, 0); win_width -= MARGIN; /* indent = ent->indent; str = ent->str; line_pos = str_pos = 0;*/ /* start from the last recorded wrap, and move forward */ indent = xtext->buffer->indent; str_pos = ent->wrap_offset[RECORD_WRAPS - 1]; str = str_pos + ent->str; line_pos = RECORD_WRAPS; do { len = find_next_wrap(xtext, ent, str, win_width, indent); indent = xtext->buffer->indent; str += len; str_pos += len; line_pos++; if (line_pos >= line) return str_pos; } while (str < ent->str + ent->str_len); return 0; } /* horrible hack for drawing time stamps */ static void gtk_xtext_render_stamp(GtkXText * xtext, textentry * ent, char *text, int len, int line, int win_width) { textentry tmp_ent; int jo, ji, hs; int xsize, y; /* trashing ent here, so make a backup first */ memcpy(&tmp_ent, ent, sizeof(tmp_ent)); ent->mb = TRUE; /* make non-english days of the week work */ jo = xtext->jump_out_offset; /* back these up */ ji = xtext->jump_in_offset; hs = xtext->hilight_start; xtext->jump_out_offset = 0; xtext->jump_in_offset = 0; xtext->hilight_start = 0xffff; /* temp disable */ if (xtext->mark_stamp) { /* if this line is marked, mark this stamp too */ if (ent->mark_start == 0) { ent->mark_start = 0; ent->mark_end = len; } else { ent->mark_start = -1; ent->mark_end = -1; } ent->str = text; } y = (xtext->fontsize * line) + xtext->font->ascent - xtext->pixel_offset; gtk_xtext_render_str(xtext, y, ent, text, NULL, len, win_width, 2, line, TRUE, &xsize); /* restore everything back to how it was */ memcpy(ent, &tmp_ent, sizeof(tmp_ent)); xtext->jump_out_offset = jo; xtext->jump_in_offset = ji; xtext->hilight_start = hs; /* with a non-fixed-width font, sometimes we don't draw enough background i.e. when this stamp is shorter than xtext->stamp_width */ xsize += MARGIN; if (xsize < xtext->stamp_width) { y -= xtext->font->ascent; xtext_draw_bg(xtext, xsize, /* x */ y, /* y */ xtext->stamp_width - xsize, /* width */ xtext->fontsize /* height */ ); } } /* render a single line, which may wrap to more lines */ static int gtk_xtext_render_line(GtkXText * xtext, textentry * ent, int line, int lines_max, int subline, int win_width) { unsigned char *str; unsigned char *attr; int indent, taken, entline, len, y, start_subline; entline = taken = 0; str = ent->str; attr = ent->fstr->attr; indent = ent->indent; start_subline = subline; #if 1 /* draw the timestamp */ if (xtext->auto_indent && xtext->buffer->time_stamp && (!xtext->skip_stamp || xtext->mark_stamp || xtext->force_stamp)) { const char *ts = timestamp_time("%H:%M:%S", ent->fstr->ts); int len = strlen(ts); gtk_xtext_render_stamp(xtext, ent, ts, len, line, win_width); } #endif /* draw each line one by one */ do { /* if it's one of the first 4 wraps, we don't need to calculate it, it's recorded in ->wrap_offset. This saves us a loop. */ if (entline < RECORD_WRAPS) { if (ent->lines_taken < 2) len = ent->str_len; else { if (entline > 0) len = ent->wrap_offset[entline] - ent->wrap_offset[entline - 1]; else len = ent->wrap_offset[0]; } } else len = find_next_wrap(xtext, ent, str, win_width, indent); entline++; y = (xtext->fontsize * line) + xtext->font->ascent - xtext->pixel_offset; if (!subline) { if (!gtk_xtext_render_str(xtext, y, ent, str, attr, len, win_width, indent, line, FALSE, NULL)) { /* small optimization */ gtk_xtext_draw_marker(xtext, ent, y - xtext->fontsize * (taken + start_subline + 1)); return ent->lines_taken - subline; } } else { xtext->dont_render = TRUE; gtk_xtext_render_str(xtext, y, ent, str, attr, len, win_width, indent, line, FALSE, NULL); xtext->dont_render = FALSE; subline--; line--; taken--; } indent = xtext->buffer->indent; line++; taken++; str += len; attr += len; if (line >= lines_max) break; } while (str < ent->str + ent->str_len); gtk_xtext_draw_marker(xtext, ent, y - xtext->fontsize * (taken + start_subline)); return taken; } void gtk_xtext_set_palette(GtkXText * xtext, GdkColor palette[]) { int i; GdkColor col; for (i = (XTEXT_COLS - 1); i >= 0; i--) { #ifdef USE_XFT xtext->color[i].color.red = palette[i].red; xtext->color[i].color.green = palette[i].green; xtext->color[i].color.blue = palette[i].blue; xtext->color[i].color.alpha = 0xffff; xtext->color[i].pixel = palette[i].pixel; #endif xtext->palette[i] = palette[i].pixel; } if (GTK_WIDGET_REALIZED(xtext)) { xtext_set_fg(xtext, xtext->fgc, XTEXT_FG); xtext_set_bg(xtext, xtext->fgc, XTEXT_BG); xtext_set_fg(xtext, xtext->bgc, XTEXT_BG); col.pixel = xtext->palette[XTEXT_MARKER]; gdk_gc_set_foreground(xtext->marker_gc, &col); } xtext->col_fore = XTEXT_FG; xtext->col_back = XTEXT_BG; } static void gtk_xtext_fix_indent(xtext_buffer * buf) { int j; /* make indent a multiple of the space width */ if (buf->indent && buf->xtext->space_width) { j = 0; while (j < buf->indent) { j += buf->xtext->space_width; } buf->indent = j; } dontscroll(buf); /* force scrolling off */ } static void gtk_xtext_recalc_widths(xtext_buffer * buf, int do_str_width) { textentry *ent; /* since we have a new font, we have to recalc the text widths */ for (ent = buf->text_first; ent; ent = ent->next) { if (do_str_width) { ent->str_width = gtk_xtext_text_width(buf->xtext, ent->str, ent->str_len, NULL); } if (ent->left_len != -1) { ent->indent = (buf->indent - gtk_xtext_text_width(buf->xtext, ent->str, ent->left_len, NULL)) - buf->xtext->space_width; if (ent->indent < MARGIN) ent->indent = MARGIN; } } gtk_xtext_calc_lines(buf, FALSE); } int gtk_xtext_set_font(GtkXText * xtext, char *name) { int i; unsigned char c; if (xtext->font) backend_font_close(xtext); /* realize now, so that font_open has a XDisplay */ gtk_widget_realize(GTK_WIDGET(xtext)); backend_font_open(xtext, name); if (xtext->font == NULL) return FALSE; /* measure the width of every char; only the ASCII ones for XFT */ for (i = 0; i < sizeof(xtext->fontwidth) / sizeof(xtext->fontwidth[0]); i++) { c = i; xtext->fontwidth[i] = backend_get_text_width(xtext, &c, 1, TRUE); } xtext->space_width = xtext->fontwidth[' ']; xtext->fontsize = xtext->font->ascent + xtext->font->descent; #if 1 { const char *time_str = timestamp("%H:%M:%S"); int stamp_size = strlen(time_str); xtext->stamp_width = gtk_xtext_text_width(xtext, time_str, stamp_size, NULL) + MARGIN; } #endif gtk_xtext_fix_indent(xtext->buffer); if (GTK_WIDGET_REALIZED(xtext)) gtk_xtext_recalc_widths(xtext->buffer, TRUE); return TRUE; } void gtk_xtext_set_background(GtkXText * xtext, GdkPixmap * pixmap, gboolean trans) { GdkGCValues val; gboolean shaded = FALSE; if (trans && (xtext->tint_red != 255 || xtext->tint_green != 255 || xtext->tint_blue != 255)) shaded = TRUE; #if !defined(USE_XLIB) && !defined(WIN32) shaded = FALSE; trans = FALSE; #endif if (xtext->pixmap) { #if defined(USE_XLIB) || defined(WIN32) if (xtext->transparent) gtk_xtext_free_trans(xtext); else #endif g_object_unref(xtext->pixmap); xtext->pixmap = NULL; } xtext->transparent = trans; #if defined(USE_XLIB) || defined(WIN32) if (trans) { xtext->shaded = shaded; if (GTK_WIDGET_REALIZED(xtext)) gtk_xtext_load_trans(xtext); return; } #endif dontscroll(xtext->buffer); xtext->pixmap = pixmap; if (pixmap != 0) { g_object_ref(pixmap); if (GTK_WIDGET_REALIZED(xtext)) { gdk_gc_set_tile(xtext->bgc, pixmap); gdk_gc_set_ts_origin(xtext->bgc, 0, 0); xtext->ts_x = xtext->ts_y = 0; gdk_gc_set_fill(xtext->bgc, GDK_TILED); } } else if (GTK_WIDGET_REALIZED(xtext)) { g_object_unref(xtext->bgc); val.subwindow_mode = GDK_INCLUDE_INFERIORS; val.graphics_exposures = 0; xtext->bgc = gdk_gc_new_with_values(GTK_WIDGET(xtext)->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext_set_fg(xtext, xtext->bgc, XTEXT_BG); } } /* count how many lines 'ent' will take (with wraps) */ static int gtk_xtext_lines_taken(xtext_buffer * buf, textentry * ent) { unsigned char *str; int indent, taken, len; int win_width; win_width = buf->window_width - MARGIN; if (ent->str_width + ent->indent < win_width) return 1; indent = ent->indent; str = ent->str; taken = 0; do { len = find_next_wrap(buf->xtext, ent, str, win_width, indent); if (taken < RECORD_WRAPS) ent->wrap_offset[taken] = (str + len) - ent->str; indent = buf->indent; taken++; str += len; } while (str < ent->str + ent->str_len); return taken; } /* Calculate number of actual lines (with wraps), to set adj->lower. * * This should only be called when the window resizes. */ static void gtk_xtext_calc_lines(xtext_buffer * buf, int fire_signal) { textentry *ent; int width; int height; int lines; gdk_drawable_get_size(GTK_WIDGET(buf->xtext)->window, &width, &height); width -= MARGIN; if (width < 30 || height < buf->xtext->fontsize || width < buf->indent + 30) return; lines = 0; for (ent = buf->text_first; ent; ent = ent->next) { ent->lines_taken = gtk_xtext_lines_taken(buf, ent); lines += ent->lines_taken; } buf->pagetop_ent = NULL; buf->num_lines = lines; gtk_xtext_adjustment_set(buf, fire_signal); } /* find the n-th line in the linked list, this includes wrap calculations */ static textentry *gtk_xtext_nth(GtkXText * xtext, int line, int *subline) { int lines = 0; textentry *ent; ent = xtext->buffer->text_first; /* -- optimization -- try to make a short-cut using the pagetop ent */ if (xtext->buffer->pagetop_ent) { if (line == xtext->buffer->pagetop_line) { *subline = xtext->buffer->pagetop_subline; return xtext->buffer->pagetop_ent; } if (line > xtext->buffer->pagetop_line) { /* lets start from the pagetop instead of the absolute beginning */ ent = xtext->buffer->pagetop_ent; lines = xtext->buffer->pagetop_line - xtext->buffer->pagetop_subline; } else if (line > xtext->buffer->pagetop_line - line) { /* move backwards from pagetop */ ent = xtext->buffer->pagetop_ent; lines = xtext->buffer->pagetop_line - xtext->buffer->pagetop_subline; while (1) { if (lines <= line) { *subline = line - lines; return ent; } ent = ent->prev; if (!ent) break; lines -= ent->lines_taken; } return NULL; } } /* -- end of optimization -- */ while (ent) { lines += ent->lines_taken; if (lines > line) { *subline = ent->lines_taken - (lines - line); return ent; } ent = ent->next; } return NULL; } /* render enta (or an inclusive range enta->entb) */ static int gtk_xtext_render_ents(GtkXText * xtext, textentry * enta, textentry * entb) { textentry *ent, *orig_ent, *tmp_ent; int line; int lines_max; int width; int height; int subline; int drawing = FALSE; if (xtext->buffer->indent < MARGIN) xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */ gdk_drawable_get_size(GTK_WIDGET(xtext)->window, &width, &height); width -= MARGIN; if (width < 32 || height < xtext->fontsize || width < xtext->buffer->indent + 30) return 0; lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + 1; line = 0; orig_ent = xtext->buffer->pagetop_ent; subline = xtext->buffer->pagetop_subline; /* used before a complete page is in buffer */ if (orig_ent == NULL) orig_ent = xtext->buffer->text_first; /* check if enta is before the start of this page */ if (entb) { for (tmp_ent = orig_ent; tmp_ent; tmp_ent = tmp_ent->next) { if (tmp_ent == enta) break; if (tmp_ent == entb) { drawing = TRUE; break; } } } for (ent = orig_ent; ent; ent = ent->next) { if (entb && ent == enta) drawing = TRUE; if (drawing || ent == entb || ent == enta) { gtk_xtext_reset(xtext, FALSE, TRUE); line += gtk_xtext_render_line(xtext, ent, line, lines_max, subline, width); subline = 0; xtext->jump_in_offset = 0; /* jump_in_offset only for the 1st */ } else { if (ent == orig_ent) { line -= subline; subline = 0; } line += ent->lines_taken; } if (ent == entb) break; if (line >= lines_max) break; } /* space below last line */ return (xtext->fontsize * line) - xtext->pixel_offset; } /* render a whole page/window, starting from 'startline' */ static void gtk_xtext_render_page(GtkXText * xtext) { textentry *ent; int line; int lines_max; int width; int height; int subline; int startline = xtext->adj->value; if (!GTK_WIDGET_REALIZED(xtext)) return; if (xtext->buffer->indent < MARGIN) xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */ gdk_drawable_get_size(GTK_WIDGET(xtext)->window, &width, &height); if (width < 34 || height < xtext->fontsize || width < xtext->buffer->indent + 32) return; #ifdef SMOOTH_SCROLL xtext->pixel_offset = (xtext->adj->value - startline) * xtext->fontsize; #else xtext->pixel_offset = 0; #endif subline = line = 0; ent = xtext->buffer->text_first; if (startline > 0) ent = gtk_xtext_nth(xtext, startline, &subline); xtext->buffer->pagetop_ent = ent; xtext->buffer->pagetop_subline = subline; xtext->buffer->pagetop_line = startline; #ifdef SCROLL_HACK { int pos, overlap; GdkRectangle area; if (xtext->buffer->num_lines <= xtext->adj->page_size) dontscroll(xtext->buffer); #ifdef SMOOTH_SCROLL pos = xtext->adj->value * xtext->fontsize; #else pos = startline * xtext->fontsize; #endif overlap = xtext->buffer->last_pixel_pos - pos; xtext->buffer->last_pixel_pos = pos; #ifdef USE_DB if (!xtext->pixmap && abs(overlap) < height) #else /* dont scroll PageUp/Down without a DB, it looks ugly */ if (!xtext->pixmap && abs(overlap) < height - (3 * xtext->fontsize)) #endif { /* so the obscured regions are exposed */ gdk_gc_set_exposures(xtext->fgc, TRUE); if (overlap < 1) { /* DOWN */ int remainder; gdk_draw_drawable(xtext->draw_buf, xtext->fgc, xtext->draw_buf, 0, -overlap, 0, 0, width, height + overlap); remainder = ((height - xtext->font->descent) % xtext->fontsize) + xtext->font->descent; area.y = (height + overlap) - remainder; area.height = remainder - overlap; } else { gdk_draw_drawable(xtext->draw_buf, xtext->fgc, xtext->draw_buf, 0, 0, 0, overlap, width, height - overlap); area.y = 0; area.height = overlap; } gdk_gc_set_exposures(xtext->fgc, FALSE); if (area.height > 0) { area.x = 0; area.width = width; gtk_xtext_paint(GTK_WIDGET(xtext), &area); } xtext->buffer->grid_dirty = TRUE; return; } } #endif xtext->buffer->grid_dirty = FALSE; width -= MARGIN; lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + 1; while (ent) { gtk_xtext_reset(xtext, FALSE, TRUE); line += gtk_xtext_render_line(xtext, ent, line, lines_max, subline, width); subline = 0; if (line >= lines_max) break; ent = ent->next; } line = (xtext->fontsize * line) - xtext->pixel_offset; /* fill any space below the last line with our background GC */ xtext_draw_bg(xtext, 0, line, width + MARGIN, height - line); /* draw the separator line */ gtk_xtext_draw_sep(xtext, -1); } void gtk_xtext_refresh(GtkXText * xtext, int do_trans) { if (GTK_WIDGET_REALIZED(GTK_WIDGET(xtext))) { #if defined(USE_XLIB) || defined(WIN32) if (xtext->transparent && do_trans) { gtk_xtext_free_trans(xtext); gtk_xtext_load_trans(xtext); } #endif gtk_xtext_render_page(xtext); } } /* remove the topline from the list */ static void gtk_xtext_remove_top(xtext_buffer * buffer) { textentry *ent; ent = buffer->text_first; if (!ent) return; buffer->num_lines -= ent->lines_taken; buffer->pagetop_line -= ent->lines_taken; buffer->last_pixel_pos -= (ent->lines_taken * buffer->xtext->fontsize); buffer->text_first = ent->next; buffer->text_first->prev = NULL; buffer->old_value -= ent->lines_taken; if (buffer->xtext->buffer == buffer) { /* is it the current buffer? */ buffer->xtext->adj->value -= ent->lines_taken; buffer->xtext->select_start_adj -= ent->lines_taken; } if (ent == buffer->pagetop_ent) buffer->pagetop_ent = NULL; if (ent == buffer->last_ent_start) buffer->last_ent_start = ent->next; if (ent == buffer->last_ent_end) { buffer->last_ent_start = NULL; buffer->last_ent_end = NULL; } if (buffer->marker_pos == ent) buffer->marker_pos = NULL; free(ent); } void gtk_xtext_clear(xtext_buffer * buf) { textentry *next; if (buf->xtext->auto_indent) buf->indent = MARGIN; buf->scrollbar_down = TRUE; buf->last_ent_start = NULL; buf->last_ent_end = NULL; buf->marker_pos = NULL; dontscroll(buf); while (buf->text_first) { next = buf->text_first->next; free(buf->text_first); buf->text_first = next; } buf->text_last = NULL; if (buf->xtext->buffer == buf) { gtk_xtext_calc_lines(buf, TRUE); gtk_xtext_refresh(buf->xtext, 0); } else { gtk_xtext_calc_lines(buf, FALSE); } } static gboolean gtk_xtext_check_ent_visibility(GtkXText * xtext, textentry * find_ent, int add) { textentry *ent; int lines_max; int line = 0; int width; int height; gdk_drawable_get_size(GTK_WIDGET(xtext)->window, &width, &height); lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + add; ent = xtext->buffer->pagetop_ent; while (ent && line < lines_max) { if (find_ent == ent) return TRUE; line += ent->lines_taken; ent = ent->next; } return FALSE; } void gtk_xtext_check_marker_visibility(GtkXText * xtext) { if (gtk_xtext_check_ent_visibility(xtext, xtext->buffer->marker_pos, 1)) xtext->buffer->marker_seen = TRUE; } static int gtk_xtext_render_page_timeout(GtkXText * xtext) { GtkAdjustment *adj = xtext->adj; xtext->add_io_tag = 0; /* less than a complete page? */ if (xtext->buffer->num_lines <= adj->page_size) { xtext->buffer->old_value = 0; adj->value = 0; gtk_xtext_render_page(xtext); } else if (xtext->buffer->scrollbar_down) { g_signal_handler_block(xtext->adj, xtext->vc_signal_tag); gtk_xtext_adjustment_set(xtext->buffer, FALSE); gtk_adjustment_set_value(adj, adj->upper - adj->page_size); g_signal_handler_unblock(xtext->adj, xtext->vc_signal_tag); xtext->buffer->old_value = adj->value; gtk_xtext_render_page(xtext); } else { gtk_xtext_adjustment_set(xtext->buffer, TRUE); if (xtext->indent_changed) { xtext->indent_changed = FALSE; gtk_xtext_render_page(xtext); } } return 0; } /* append a textentry to our linked list */ static void gtk_xtext_append_entry(xtext_buffer * buf, textentry * ent) { unsigned int mb; /* xchat->ekg2, note: i removed here strtr(ent->str, '\t', ' ') * coz we should pass here only fstring_t, where fstring_t can't have \t */ ent->str_width = gtk_xtext_text_width(buf->xtext, ent->str, ent->str_len, &mb); ent->mb = FALSE; if (mb) ent->mb = TRUE; ent->mark_start = -1; ent->mark_end = -1; ent->next = NULL; if (ent->indent < MARGIN) ent->indent = MARGIN; /* 2 pixels is the left margin */ /* append to our linked list */ if (buf->text_last) buf->text_last->next = ent; else buf->text_first = ent; ent->prev = buf->text_last; buf->text_last = ent; ent->lines_taken = gtk_xtext_lines_taken(buf, ent); buf->num_lines += ent->lines_taken; if (buf->reset_marker_pos || ((buf->marker_pos == NULL || buf->marker_seen) && (buf->xtext->buffer != buf || #if GTK_CHECK_VERSION(2,4,0) !gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(buf->xtext)))) #else !(GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(buf->xtext))))-> has_focus #endif ))) { buf->marker_pos = ent; dontscroll(buf); /* force scrolling off */ buf->marker_seen = FALSE; buf->reset_marker_pos = FALSE; } if (buf->xtext->max_lines > 2 && buf->xtext->max_lines < buf->num_lines) { gtk_xtext_remove_top(buf); } if (buf->xtext->buffer == buf) { #ifdef SCROLL_HACK /* this could be improved */ if ((buf->num_lines - 1) <= buf->xtext->adj->page_size) dontscroll(buf); #endif if (!buf->xtext->add_io_tag) { /* remove scrolling events */ if (buf->xtext->io_tag) { g_source_remove(buf->xtext->io_tag); buf->xtext->io_tag = 0; } buf->xtext->add_io_tag = g_timeout_add(REFRESH_TIMEOUT * 2, (GSourceFunc) gtk_xtext_render_page_timeout, buf->xtext); } } else if (buf->scrollbar_down) { buf->old_value = buf->num_lines - buf->xtext->adj->page_size; if (buf->old_value < 0) buf->old_value = 0; } } /* XXX: gtk_xtext_append(), gtk_xtext_append_indent() */ void gtk_xtext_append_fstring(xtext_buffer *buf, fstring_t fstr) { textentry *ent; int space; int tempindent; size_t len = strlen(fstr->str); if (len >= sizeof(buf->xtext->scratch_buffer)) len = sizeof(buf->xtext->scratch_buffer) - 1; ent = xmalloc(sizeof(textentry)); ent->fstr = fstr; /* NOTE, xchat create new string with str[0] = ' ' str[1...] = str[0...] * i don't know why, but without it, ui looks ugly. * * slowdown, hack. */ ent->fstr->str = xrealloc(ent->fstr->str, sizeof(char) * (len+2)); memmove(ent->fstr->str+1, ent->fstr->str, len); ent->fstr->str[0] = ' '; ent->fstr->str[len+1] = '\0'; ent->fstr->attr = xrealloc(ent->fstr->attr, sizeof(char) * (len+1)); memmove(ent->fstr->attr+1, ent->fstr->attr, len*sizeof(char)); ent->fstr->attr[0] = 128; ent->left_len = 0; ent->str = fstr->str; ent->str_len = len+1; ent->indent = (buf->indent) - buf->xtext->space_width; if (buf->time_stamp) space = buf->xtext->stamp_width; else space = 0; /* do we need to auto adjust the separator position? */ if (buf->xtext->auto_indent && ent->indent < MARGIN + space) { tempindent = MARGIN + space + buf->xtext->space_width; if (tempindent > buf->indent) buf->indent = tempindent; if (buf->indent > buf->xtext->max_auto_indent) buf->indent = buf->xtext->max_auto_indent; gtk_xtext_fix_indent(buf); gtk_xtext_recalc_widths(buf, FALSE); ent->indent = (buf->indent) - buf->xtext->space_width; buf->xtext->indent_changed = TRUE; } gtk_xtext_append_entry(buf, ent); } void gtk_xtext_set_error_function(GtkXText * xtext, void (*error_function) (int)) { xtext->error_function = error_function; } void gtk_xtext_set_indent(GtkXText * xtext, gboolean indent) { xtext->auto_indent = indent; } void gtk_xtext_set_max_indent(GtkXText * xtext, int max_auto_indent) { xtext->max_auto_indent = max_auto_indent; } void gtk_xtext_set_max_lines(GtkXText * xtext, int max_lines) { xtext->max_lines = max_lines; } void gtk_xtext_set_show_marker(GtkXText * xtext, gboolean show_marker) { xtext->marker = show_marker; } void gtk_xtext_set_show_separator(GtkXText * xtext, gboolean show_separator) { xtext->separator = show_separator; } void gtk_xtext_set_thin_separator(GtkXText * xtext, gboolean thin_separator) { xtext->thinline = thin_separator; } void gtk_xtext_set_time_stamp(xtext_buffer * buf, gboolean time_stamp) { buf->time_stamp = time_stamp; } void gtk_xtext_set_tint(GtkXText * xtext, int tint_red, int tint_green, int tint_blue) { xtext->tint_red = tint_red; xtext->tint_green = tint_green; xtext->tint_blue = tint_blue; /*if (xtext->tint_red != 255 || xtext->tint_green != 255 || xtext->tint_blue != 255) shaded = TRUE; */ } void gtk_xtext_set_urlcheck_function(GtkXText * xtext, int (*urlcheck_function) (GtkWidget *, char *, int)) { xtext->urlcheck_function = urlcheck_function; } void gtk_xtext_set_wordwrap(GtkXText * xtext, gboolean wordwrap) { xtext->wordwrap = wordwrap; } void gtk_xtext_reset_marker_pos(GtkXText * xtext) { xtext->buffer->marker_pos = NULL; dontscroll(xtext->buffer); /* force scrolling off */ gtk_xtext_render_page(xtext); xtext->buffer->reset_marker_pos = TRUE; } void gtk_xtext_buffer_show(GtkXText * xtext, xtext_buffer * buf, int render) { int w, h; buf->xtext = xtext; if (xtext->buffer == buf) return; /*printf("text_buffer_show: xtext=%p buffer=%p\n", xtext, buf);*/ if (xtext->add_io_tag) { g_source_remove(xtext->add_io_tag); xtext->add_io_tag = 0; } if (xtext->io_tag) { g_source_remove(xtext->io_tag); xtext->io_tag = 0; } if (!GTK_WIDGET_REALIZED(GTK_WIDGET(xtext))) gtk_widget_realize(GTK_WIDGET(xtext)); gdk_drawable_get_size(GTK_WIDGET(xtext)->window, &w, &h); /* after a font change */ if (buf->needs_recalc) { buf->needs_recalc = FALSE; gtk_xtext_recalc_widths(buf, TRUE); } /* now change to the new buffer */ xtext->buffer = buf; dontscroll(buf); /* force scrolling off */ xtext->adj->value = buf->old_value; xtext->adj->upper = buf->num_lines; if (xtext->adj->upper == 0) { xtext->adj->upper = 1; /* sanity check */ } else if (xtext->adj->value > xtext->adj->upper - xtext->adj->page_size) { /*buf->pagetop_ent = NULL; */ xtext->adj->value = xtext->adj->upper - xtext->adj->page_size; if (xtext->adj->value < 0) xtext->adj->value = 0; } if (render) { /* did the window change size since this buffer was last shown? */ if (buf->window_width != w) { buf->window_width = w; gtk_xtext_calc_lines(buf, FALSE); if (buf->scrollbar_down) gtk_adjustment_set_value(xtext->adj, xtext->adj->upper - xtext->adj->page_size); } else if (buf->window_height != h) { buf->window_height = h; buf->pagetop_ent = NULL; gtk_xtext_adjustment_set(buf, FALSE); } gtk_xtext_render_page(xtext); gtk_adjustment_changed(xtext->adj); } else { /* avoid redoing the transparency */ xtext->avoid_trans = TRUE; } } xtext_buffer *gtk_xtext_buffer_new(GtkXText * xtext) { xtext_buffer *buf = xmalloc(sizeof(xtext_buffer)); buf->old_value = -1; buf->xtext = xtext; buf->scrollbar_down = TRUE; buf->indent = xtext->space_width * 2; dontscroll(buf); return buf; } void gtk_xtext_buffer_free(xtext_buffer * buf) { textentry *ent; if (buf->xtext->buffer == buf) buf->xtext->buffer = buf->xtext->orig_buffer; if (buf->xtext->selection_buffer == buf) buf->xtext->selection_buffer = NULL; for (ent = buf->text_first; ent;) { textentry *next = ent->next; free(ent); /* XXX, fstring_t */ ent = next; } free(buf); } /* gtk_xtext_search() XXX, lastlog */ /* gtk_xtext_save() XXX? */ /* gtk_xtext_lastlog() XXX */ /* gtk_xtext_foreach() */ /* gtk_xtext_is_empty() */ ekg-1.9~pre+r2855/src/ui-gtk-xtext.h000066400000000000000000000161241174410337000171350ustar00rootroot00000000000000#ifndef __XTEXT_H__ #define __XTEXT_H__ #include #ifdef USE_XFT #include #endif #ifdef USE_SHM #include #include #include #include #endif #include "themes.h" #define GTK_TYPE_XTEXT (gtk_xtext_get_type ()) #define GTK_XTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_XTEXT, GtkXText)) #define GTK_XTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_XTEXT, GtkXTextClass)) #define GTK_IS_XTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_XTEXT)) #define GTK_IS_XTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XTEXT)) #define GTK_XTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_XTEXT, GtkXTextClass)) /* these match palette.h */ #define XTEXT_MIRC_COLS 32 #define XTEXT_COLS 37 /* 32 plus 5 for extra stuff below */ #define XTEXT_MARK_FG 32 /* for marking text */ #define XTEXT_MARK_BG 33 #define XTEXT_FG 34 #define XTEXT_BG 35 #define XTEXT_MARKER 36 /* for marker line */ typedef struct _GtkXText GtkXText; typedef struct _GtkXTextClass GtkXTextClass; typedef struct textentry textentry; typedef struct { GtkXText *xtext; /* attached to this widget */ gfloat old_value; /* last known adj->value */ textentry *text_first; textentry *text_last; guint16 grid_offset[256]; textentry *last_ent_start; /* this basically describes the last rendered */ textentry *last_ent_end; /* selection. */ int last_offset_start; int last_offset_end; int last_pixel_pos; int pagetop_line; int pagetop_subline; textentry *pagetop_ent; /* what's at xtext->adj->value */ int num_lines; int indent; /* position of separator (pixels) from left */ textentry *marker_pos; int window_width; /* window size when last rendered. */ int window_height; unsigned int time_stamp:1; unsigned int scrollbar_down:1; unsigned int needs_recalc:1; unsigned int grid_dirty:1; unsigned int marker_seen:1; unsigned int reset_marker_pos:1; } xtext_buffer; struct _GtkXText { GtkWidget widget; xtext_buffer *buffer; xtext_buffer *orig_buffer; xtext_buffer *selection_buffer; #ifdef USE_SHM XShmSegmentInfo shminfo; #endif GtkAdjustment *adj; GdkPixmap *pixmap; /* 0 = use palette[19] */ GdkDrawable *draw_buf; /* points to ->window */ GdkCursor *hand_cursor; GdkCursor *resize_cursor; int pixel_offset; /* amount of pixels the top line is chopped by */ int last_win_x; int last_win_y; int last_win_h; int last_win_w; int tint_red; int tint_green; int tint_blue; GdkGC *bgc; /* backing pixmap */ GdkGC *fgc; /* text foreground color */ GdkGC *light_gc; /* sep bar */ GdkGC *dark_gc; GdkGC *thin_gc; GdkGC *marker_gc; gulong palette[XTEXT_COLS]; gint io_tag; /* for delayed refresh events */ gint add_io_tag; /* "" when adding new text */ gint scroll_tag; /* marking-scroll timeout */ gulong vc_signal_tag; /* signal handler for "value_changed" adj */ int select_start_adj; /* the adj->value when the selection started */ int select_start_x; int select_start_y; int select_end_x; int select_end_y; int max_lines; int col_fore; int col_back; int depth; /* gdk window depth */ char num[8]; /* for parsing mirc color */ int nc; /* offset into xtext->num */ textentry *hilight_ent; int hilight_start; int hilight_end; guint16 fontwidth[128]; /* each char's width, only the ASCII ones */ #ifdef USE_XFT XftColor color[XTEXT_COLS]; XftColor *xft_fg; XftColor *xft_bg; /* both point into color[20] */ XftDraw *xftdraw; XftFont *font; XftFont *ifont; /* italics */ #else struct pangofont { PangoFontDescription *font; PangoFontDescription *ifont; /* italics */ int ascent; int descent; } *font, pango_font; PangoLayout *layout; #endif int fontsize; int space_width; /* width (pixels) of the space " " character */ int stamp_width; /* width of "[88:88:88]" */ int max_auto_indent; unsigned char scratch_buffer[4096]; void (*error_function) (int type); int (*urlcheck_function) (GtkWidget *xtext, char *word, int len); int jump_out_offset; /* point at which to stop rendering */ int jump_in_offset; /* "" start rendering */ int ts_x; /* ts origin for ->bgc GC */ int ts_y; int clip_x; /* clipping (x directions) */ int clip_x2; /* from x to x2 */ int clip_y; /* clipping (y directions) */ int clip_y2; /* from y to y2 */ /* current text states */ unsigned int bold:1; unsigned int underline:1; unsigned int italics:1; /* text parsing states */ unsigned int backcolor:1; /* various state information */ unsigned int moving_separator:1; unsigned int word_or_line_select:1; unsigned int button_down:1; unsigned int hilighting:1; unsigned int dont_render:1; unsigned int dont_render2:1; unsigned int cursor_hand:1; unsigned int cursor_resize:1; unsigned int skip_border_fills:1; unsigned int skip_stamp:1; unsigned int mark_stamp:1; /* Cut&Paste with stamps? */ unsigned int force_stamp:1; /* force redrawing it */ unsigned int render_hilights_only:1; unsigned int in_hilight:1; unsigned int un_hilight:1; unsigned int recycle:1; unsigned int avoid_trans:1; unsigned int indent_changed:1; unsigned int shm:1; /* settings/prefs */ unsigned int auto_indent:1; unsigned int thinline:1; unsigned int transparent:1; unsigned int shaded:1; unsigned int marker:1; unsigned int separator:1; unsigned int wordwrap:1; unsigned int overdraw:1; }; struct _GtkXTextClass { GtkWidgetClass parent_class; void (*word_click) (GtkXText * xtext, char *word, GdkEventButton * event); }; GtkWidget *gtk_xtext_new(GdkColor palette[], int separator); void gtk_xtext_append_fstring(xtext_buffer *buf, fstring_t fstr); int gtk_xtext_set_font(GtkXText * xtext, char *name); void gtk_xtext_set_background(GtkXText * xtext, GdkPixmap * pixmap, gboolean trans); void gtk_xtext_set_palette(GtkXText * xtext, GdkColor palette[]); void gtk_xtext_clear(xtext_buffer * buf); void gtk_xtext_refresh(GtkXText * xtext, int do_trans); void gtk_xtext_reset_marker_pos(GtkXText * xtext); typedef void (*GtkXTextForeach) (GtkXText * xtext, unsigned char *text, void *data); void gtk_xtext_set_error_function(GtkXText * xtext, void (*error_function) (int)); void gtk_xtext_set_indent(GtkXText * xtext, gboolean indent); void gtk_xtext_set_max_indent(GtkXText * xtext, int max_auto_indent); void gtk_xtext_set_max_lines(GtkXText * xtext, int max_lines); void gtk_xtext_set_show_marker(GtkXText * xtext, gboolean show_marker); void gtk_xtext_set_show_separator(GtkXText * xtext, gboolean show_separator); void gtk_xtext_set_thin_separator(GtkXText * xtext, gboolean thin_separator); void gtk_xtext_set_time_stamp(xtext_buffer * buf, gboolean timestamp); void gtk_xtext_set_tint(GtkXText * xtext, int tint_red, int tint_green, int tint_blue); void gtk_xtext_set_urlcheck_function(GtkXText * xtext, int (*urlcheck_function) (GtkWidget *, char *, int)); void gtk_xtext_set_wordwrap(GtkXText * xtext, gboolean word_wrap); xtext_buffer *gtk_xtext_buffer_new(GtkXText * xtext); void gtk_xtext_buffer_free(xtext_buffer * buf); void gtk_xtext_buffer_show(GtkXText * xtext, xtext_buffer * buf, int render); GtkType gtk_xtext_get_type(void); #endif ekg-1.9~pre+r2855/src/ui-gtk.c000066400000000000000000000430521174410337000157560ustar00rootroot00000000000000#include #include #include #include #include "commands.h" #include "stuff.h" #include "userlist.h" #include "xmalloc.h" #include "themes.h" #include "ui.h" /* #include "xtext.h" #include "gtkutil.h" #include "menu.h" #include "bindings.h" #include "userlistgui.h" */ #include "ui-gtk.h" #include "ui-gtk-chanview.h" #include "ui-gtk-xtext.h" #include "ui-gtk-palette.h" static int ui_gtk_inited = 0; /* czy zainicjowano? */ struct window *window_current; /* wskaĹşnik na aktualne okno */ struct window *window_status; list_t windows = NULL; /* lista okien */ char *history[HISTORY_MAX]; /* zapamiętane linie */ int history_index = 0; /* offset w historii */ /* vars */ const char font_normal_config[] = "Monospace 9"; int mainwindow_width_config = 640; int mainwindow_height_config = 400; int gui_tweaks_config = 0; int tab_small_config = 0; int tab_layout_config = 2; int tint_red_config = 195; int tint_green_config = 195; int tint_blue_config = 195; int wordwrap_config = 1; int indent_nicks_config = 1; int show_separator_config = 1; int max_auto_indent_config = 255; int gui_ulist_pos_config = 3; int tab_pos_config = 6; int show_marker_config = 1; int thin_separator_config = 1; int gui_pane_left_size_config = 100; int gui_pane_right_size_config = 100; int hidemenu_config = 0; #define newtabstofront_config 2 /* ekg2-core var */ #define config_timestamp_show 1 int new_window_in_tab_config = 1; /* forward */ void fe_set_tab_color(window_t *sess, int col); void mg_switch_page(int relative, int num); void mg_apply_setup(void); /* BUGS/ FEATURES NOT IMPLEMENTED, * ncurses window_printat() * ncurses /window dump */ /************************************************************************************ * FUNCTIONS COPIED FROM UI-NCURSES ************************************************************************************/ /* * window_switch() * * przełącza do podanego okna. */ static void window_switch(int id) { static int lock = 0; list_t l; if (lock) return; lock = 1; for (l = windows; l; l = l->next) { struct window *w = l->data; if (id != w->id) continue; window_current = w; w->act = 0; mg_switch_page(0, w->id); fe_set_tab_color(w, 0 /* w->act */); break; } lock = 0; } /* * window_find() * * szuka okna o podanym celu. zwraca strukturę opisującą je. */ static struct window *window_find(const char *target) { list_t l; int current = ((target) ? !strcasecmp(target, "$") || !strcasecmp(target, "__current") : 0); int debug = ((target) ? !strcasecmp(target, "__debug") : 0); int status = ((target) ? !strcasecmp(target, "__status") : 0); struct userlist *u = NULL; if (!target || current) { if (window_current->id) return window_current; else status = 1; } if (target) u = userlist_find(get_uin(target), NULL); for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->id && debug) return w; if (w->id == 1 && status) return w; if (w->target && target) { if (!strcasecmp(target, w->target)) return w; if (u && u->display && !strcasecmp(u->display, w->target)) return w; if (u && !strcasecmp(itoa(u->uin), w->target)) return w; } } return NULL; } static void window_next() { struct window *next = NULL; int passed = 0; list_t l; for (l = windows; l; l = l->next) { if (l->data == window_current) passed = 1; if (passed && l->next) { struct window *w = l->next->data; next = w; break; } } if (!next) next = window_find("__status"); window_switch(next->id); } static void window_prev() { struct window *prev = NULL; list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w == window_current && l != windows) break; prev = l->data; } if (!prev->id) { for (l = windows; l; l = l->next, prev = l->data); } window_switch(prev->id); } void ui_gtk_window_clear(struct window *w) { gtk_xtext_clear(gtk_private(window_current)->buffer); } /* * window_new_compare() * * do sortowania okienek. */ static int window_new_compare(void *data1, void *data2) { struct window *a = data1, *b = data2; if (!a || !b) return 0; return a->id - b->id; } /* * window_new() * * tworzy nowe okno o podanej nazwie i id. */ static struct window *window_new(const char *target, int new_id) { struct window *w; int id = 1, done = 0; list_t l; struct userlist *u = NULL; if (target) { struct window *w = window_find(target); if (w) return w; u = userlist_find(0, target); if (!strcmp(target, "$")) return window_current; } if (target && *target == '*' && !u) id = 100; while (!done) { done = 1; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id == id) { done = 0; id++; break; } } } if (new_id != 0) id = new_id; /* okno z debug'iem */ if (id == -1) id = 0; w = xmalloc(sizeof(struct window)); w->id = id; w->last_act_time = time(NULL); if (target) { if (*target == '+' && !u) { /* w->doodle = 1; */ w->target = xstrdup(target + 1); } else if (*target == '*' && !u) { const char *tmp = strchr(target, '/'); if (!tmp) tmp = ""; w->target = xstrdup(tmp); /* ui-gtk windows don't support frames */ /* char **argv, **arg; argv = arg = array_make(target + 1, ",", 5, 0, 0); if (*arg && *arg[0] != '/') w->frames = atoi(*arg); array_free(argv); */ } else { w->target = xstrdup(target); w->prompt = format_string(format_find("ncurses_prompt_query"), target); w->prompt_len = strlen(w->prompt); } } else { const char *f = format_find("ncurses_prompt_none"); if (strcmp(f, "")) { w->prompt = xstrdup(f); w->prompt_len = strlen(w->prompt); } } list_add_sorted(&windows, w, 0, window_new_compare); /* w.window */ mg_changui_new(w, new_window_in_tab_config, 0); return w; } /* * window_kill() * * usuwa podane okno. */ static void window_kill(struct window *w, int quiet) { int id = w->id; if (quiet) goto cleanup; if (id == 1 && w->target) { printq("query_finished", window_current->target); return; } if (id == 1) { printq("window_kill_status"); return; } if (id == 0) return; if (w == window_current) window_prev(); if (config_sort_windows) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id > 1 && w->id > id) w->id--; } } cleanup: if (w == window_current) window_current = NULL; xfree(w->target); fe_close_window(w); list_remove(&windows, w, 1); } /**************************************************************************************************/ /* * ui_gtk_beep() * * ostentacyjnie wzywa uĹźytkownika do reakcji. */ static void ui_gtk_beep() { #warning "XXX" /* XXX, * config_beep_title? * - zrobic miganie w trayu? * - miganie okienka? */ gdk_beep(); } /* * ui_gtk_loop() * * główna pętla interfejsu. */ static void ui_gtk_loop() { #define ui_quit 0 do { ekg_wait_for_key(); while (gtk_events_pending()) { gtk_main_iteration(); } } while (ui_quit == 0); } static int ui_gtk_event_command(const char *command, int quiet, va_list ap) { if (!strcasecmp(command, "window")) { char *p1 = va_arg(ap, char*); char *p2 = va_arg(ap, char*); if (!p1 || !strcasecmp(p1, "list")) { int num = p2 ? atoi(p2) : 0; list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id && (!p2 || w->id == num)) { if (w->target) { #warning "Tutaj, wyswietlic gdy okno jest toplevel, lub odlaczone" printq("window_list_query", itoa(w->id), w->target); } else printq("window_list_nothing", itoa(w->id)); } } return 0; } if (!strcasecmp(p1, "active")) { list_t l; int id = 0; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->act && w->id) { id = w->id; break; } } if (id) window_switch(id); return 0; } if (!strcasecmp(p1, "new")) { struct window *w = window_new(p2, 0); window_switch(w->id); return 0; } if (!strcasecmp(p1, "switch")) { if (!p2) { printq("not_enough_params", "window"); return -1; } window_switch(atoi(p2)); return 0; } if (!strcasecmp(p1, "kill")) { struct window *w = window_current; if (p2) { list_t l; for (w = NULL, l = windows; l; l = l->next) { struct window *ww = l->data; if (ww->id == atoi(p2)) { w = ww; break; } } if (!w) { printq("window_noexist"); return -1; } } window_kill(w, 0); return 0; } if (!strcasecmp(p1, "next")) { window_next(); return 0; } if (!strcasecmp(p1, "prev")) { window_prev(); return 0; } if (!strcasecmp(p1, "clear")) { ui_gtk_window_clear(window_current); return 0; } printq("invalid_params", "window"); return -1; } if (!strcasecmp(command, "query")) { char *param = va_arg(ap, char*); if (!param && !window_current->target) return -1; if (param) { struct window *w; if ((w = window_find(param))) { window_switch(w->id); return -1; } if ((config_make_window & 3) == 1) { list_t l; for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->id < 2 || v->target) continue; w = v; break; } if (!w) w = window_new(param, 0); window_switch(w->id); } if ((config_make_window & 3) == 2) { w = window_new(param, 0); window_switch(w->id); } xfree(window_current->target); xfree(window_current->prompt); window_current->target = xstrdup(param); window_current->prompt = format_string(format_find("ncurses_prompt_query"), param); window_current->prompt_len = strlen(window_current->prompt); if (!quiet) { print_window(param, 0, "query_started", param); print_window(param, 0, "query_started_window", param); } } else { const char *f = format_find("ncurses_prompt_none"); printq("query_finished", window_current->target); xfree(window_current->target); xfree(window_current->prompt); window_current->target = NULL; window_current->prompt = NULL; window_current->prompt_len = 0; if (strcmp(f, "")) { window_current->prompt = xstrdup(f); window_current->prompt_len = strlen(f); } } return -1; } return 0; } static int ui_gtk_event_variable_changed(const char *name, va_list ap) { #if 0 if (!strncasecmp(name, "contacts", 8)) contacts_changed(); #endif if (!strcmp(name, "uin")) { /* XXX, for each window */ gtk_label_set_label(GTK_LABEL(gtk_private_ui(window_status)->nick_label), itoa(config_uin)); } return 0; } extern gboolean mg_populate_userlist(window_t *sess); extern gboolean fe_userlist_rehash(struct window *sess, void *data); static int ui_gtk_event(const char *event, ...) { va_list ap; if (!event) return 0; va_start(ap, event); if (!strcmp(event, "command")) { int quiet = va_arg(ap, int); char *command = va_arg(ap, char*); ui_gtk_event_command(command, quiet, ap); } else if (!strcmp(event, "variable_changed")) { char *name = va_arg(ap, char*); ui_gtk_event_variable_changed(name, ap); } else if (!strcmp(event, "status")) { /* uin, display, status, descr */ uin_t uin = va_arg(ap, uin_t); struct userlist *u = userlist_find(uin, NULL); if (u && u->display) ui_gtk_foreach_window_data(fe_userlist_rehash, u); } else if (!strcmp(event, "userlist_changed")) { /* nick, uin, NULL */ /* XXX, * w handle_userlist()::GG_USERLIST_GET_REPLY * nie informujemy o tym ze userow kasujemy. * Tylko dodajemy nowych. W zwiazku z tym trzeba zrobic przebudowanie calej userlist * * W sumie nic strasznego, bo nawet taki /del * jest (przynajmniej u mnie) atomowy. */ ui_gtk_foreach_window(mg_populate_userlist); } va_end(ap); return 0; } /* * ui_gtk_postinit() * * uruchamiana po wczytaniu konfiguracji. */ static void ui_gtk_postinit() { #if 0 if (config_windows_save && config_windows_layout) { char **targets = array_make(config_windows_layout, "|", 0, 0, 0); int i; if (targets[0] && strcmp(targets[0], "")) { xfree(window_current->target); xfree(window_current->prompt); window_current->target = xstrdup(targets[0]); window_current->prompt = format_string(format_find("ncurses_prompt_query"), targets[0]); window_current->prompt_len = strlen(window_current->prompt); } for (i = 1; targets[i]; i++) { if (!strcmp(targets[i], "-")) continue; window_new((strcmp(targets[i], "")) ? targets[i] : NULL, i + 1); } array_free(targets); } #endif mg_apply_setup(); mg_switch_page(FALSE, window_current->id); ui_gtk_foreach_window(mg_populate_userlist); } void ui_gtk_foreach_window_data(int (*func)(struct window *, void *data), void *data) { list_t l; int once = 0; for (l = windows; l; l = l->next) { window_t *w = l->data; if (w->gui->is_tab) { if (!once) once = 1; else continue; } if (func(w, data)) return; } } void ui_gtk_foreach_window(int (*func)(struct window *)) { list_t l; int once = 0; for (l = windows; l; l = l->next) { window_t *w = l->data; if (w->gui->is_tab) { if (!once) once = 1; else continue; } if (func(w)) return; } } /* function copied from ui-ncurses */ static void ui_gtk_print(const char *target, int separate, const char *line) { struct window *w; fstring_t fs; list_t l; char *lines, *lines_save, *line2; string_t speech = NULL; time_t cur_time; switch (config_make_window & 3) { case 1: if ((w = window_find(target))) goto crap; if (!separate) w = window_find("__status"); for (l = windows; l; l = l->next) { struct window *w = l->data; if (separate && !w->target && w->id > 1) { w->target = xstrdup(target); xfree(w->prompt); w->prompt = format_string(format_find("ncurses_prompt_query"), target); w->prompt_len = strlen(w->prompt); print("window_id_query_started", itoa(w->id), target); print_window(target, 1, "query_started", target); print_window(target, 1, "query_started_window", target); if (get_uin(target) && !(ignored_check(get_uin(target)) & IGNORE_EVENTS)) event_check(EVENT_QUERY, get_uin(target), target); break; } } case 2: if (!(w = window_find(target))) { if (!separate) w = window_find("__status"); else { w = window_new(target, 0); print("window_id_query_started", itoa(w->id), target); print_window(target, 1, "query_started", target); print_window(target, 1, "query_started_window", target); if (get_uin(target) && !(ignored_check(get_uin(target)) & IGNORE_EVENTS)) event_check(EVENT_QUERY, get_uin(target), target); } } crap: if (!config_display_crap && target && !strcmp(target, "__current")) w = window_find("__status"); break; default: /* jeśli nie ma okna, rzuć do statusowego. */ if (!(w = window_find(target))) w = window_find("__status"); } /* albo zaczynamy, albo kończymy i nie ma okienka Ĺźadnego */ if (!w) return; cur_time = time(NULL); if (config_speech_app) speech = string_init(NULL); if (config_display_daychanges) { int day_win, day_cur; day_win = localtime(&w->last_act_time)->tm_yday; day_cur = localtime(&cur_time)->tm_yday; if (cur_time > w->last_act_time && day_win != day_cur) { struct tm *tm; char *tmp, *fmt, *tmp2; char str_win[12], str_cur[12]; fmt = (config_datestamp) ? config_datestamp : "%Y-%m-%d"; tm = localtime(&w->last_act_time); strftime (str_win, sizeof(str_win), fmt, tm); tm = localtime(&cur_time); strftime (str_cur, sizeof(str_cur), fmt, tm); tmp = format_string(format_find("window_day_changed"), str_win, str_cur); if ((tmp2 = strchr(tmp, '\n'))) *tmp2 = 0; fs = reformat_string(tmp); fs->ts = cur_time; if (config_speech_app) { string_append(speech, fs->str); string_append_c(speech, '\n'); } gtk_xtext_append_fstring(w->buffer, fs); xfree(tmp); } } w->last_act_time = cur_time; if (w != window_current) { if (!w->act) { w->act = 1; w->first_act_time = w->last_act_time; } } /* XXX wyrzucić dzielenie na linie z ui do ekg */ lines = lines_save = xstrdup(line); while ((line2 = get_line(&lines))) { fs = reformat_string(line2); fs->ts = cur_time; if (config_speech_app) { string_append(speech, fs->str); string_append_c(speech, '\n'); } gtk_xtext_append_fstring(w->buffer, fs); } xfree(lines_save); if (config_speech_app && w->id) say_it(speech->str); string_free(speech, 1); } static void ui_gtk_deinit() { list_t l; int i; if (!ui_gtk_inited) return; ui_gtk_inited = 0; for (l = windows; l; ) { struct window *w = l->data; l = l->next; window_kill(w, 1); } list_destroy(windows, 1); for (i = 0; i < HISTORY_MAX; i++) { xfree(history[i]); history[i] = NULL; } } void ui_gtk_window_switch(int id) { window_switch(id); } void ui_gtk_window_kill(struct window *w, int quiet) { window_kill(w, quiet); } void ui_gtk_window_new(const char *target, int new_id) { window_new(target, new_id); } void ui_gtk_init() { const char no_display[] = "Zmienna $DISPLAY nie jest ustawiona\nInicjalizacja gtk napewno niemozliwa...\n"; if (!getenv("DISPLAY")) { fprintf(stderr, no_display); /* fallback na inne ui? */ return; } if (!(gtk_init_check(0, NULL))) { /* fallback na inne ui? */ return; } #ifndef GG_DEBUG_DISABLE window_new(NULL, -1); #endif window_current = window_status = window_new(NULL, 0); ui_gtk_inited = 1; ui_loop = ui_gtk_loop; ui_beep = ui_gtk_beep; ui_postinit = ui_gtk_postinit; ui_event = ui_gtk_event; ui_print = ui_gtk_print; ui_deinit = ui_gtk_deinit; pixmaps_init(); } ekg-1.9~pre+r2855/src/ui-gtk.h000066400000000000000000000077551174410337000157750ustar00rootroot00000000000000#ifndef UI_GTK_H #define UI_GTK_H #include #include #include typedef struct { GtkWidget *xtext, *vscrollbar, *window, /* toplevel */ *topic_entry, *note_book, *main_table, *user_tree, /* GtkTreeView */ *user_box, /* userlist box */ *dialogbutton_box, *topicbutton_box, *topic_bar, *hpane_left, *hpane_right, *vpane_left, *vpane_right, *menu, *bar, /* connecting progress bar */ *nick_box, /* contains label to the left of input_box */ *nick_label, *op_xpm, /* icon to the left of nickname */ *namelistinfo, /* label above userlist */ *input_box; #define MENU_ID_NUM 12 GtkWidget *menu_item[MENU_ID_NUM + 1]; /* some items we may change state of */ void *chanview; /* chanview.h */ int pane_left_size; /*last position of the pane */ int pane_right_size; guint16 is_tab; /* is tab or toplevel? */ guint16 ul_hidden; /* userlist hidden? */ } gtk_window_ui_t; typedef struct window { int last_update; /* czas ostatniego uaktualnienia */ char *target; /* nick query albo inna nazwa albo NULL */ int id; /* numer okna */ int act; /* czy coś się zmieniło? */ time_t first_act_time; /* timestamp zmiany act */ time_t last_act_time; /* timestamp ostatniej aktywności */ char *prompt; /* sformatowany prompt lub NULL */ int prompt_len; /* długość prompta lub 0 */ /* gtk window */ gtk_window_ui_t *gui; void *tab; /* (chan *) */ /* information stored when this tab isn't front-most */ void *user_model; /* for filling the GtkTreeView */ void *buffer; /* xtext_Buffer */ gfloat old_ul_value; /* old userlist value (for adj) */ } window_t; enum { POS_INVALID = 0, POS_TOPLEFT = 1, POS_BOTTOMLEFT = 2, POS_TOPRIGHT = 3, POS_BOTTOMRIGHT = 4, POS_TOP = 5, /* for tabs only */ POS_BOTTOM = 6, POS_HIDDEN = 7 }; #define gtk_private(w) (w) #define gtk_private_ui(w) (w->gui) extern struct window *window_current; /* wskaĹşnik na aktualne okno */ extern struct window *window_status; extern list_t windows; /* lista okien */ #define HISTORY_MAX 1000 /* maksymalna ilość wpisĂłw historii */ extern char *history[HISTORY_MAX]; /* zapamiętane linie */ extern int history_index; /* offset w historii */ extern const char font_normal_config[]; extern int mainwindow_width_config; extern int mainwindow_height_config; extern int gui_tweaks_config; extern int tab_small_config; extern int gui_pane_right_size_config; extern int tab_layout_config; extern int show_marker_config; extern int tint_red_config; extern int tint_green_config; extern int tint_blue_config; extern int wordwrap_config; extern int indent_nicks_config; extern int show_separator_config; extern int max_auto_indent_config; extern int gui_ulist_pos_config; extern int tab_pos_config; extern int gui_pane_left_size_config; extern int gui_pane_right_size_config; extern int thin_separator_config; extern int new_window_in_tab_config; extern int hidemenu_config; #define mainwindow_left_config 0 #define mainwindow_top_config 0 #define chanmodebuttons_config -1 #define gui_win_state_config 0 #define newtabstofront_config 2 #define gui_quit_dialog_config -1 #define truncchans_config 20 #define tab_sort_config 1 #define tab_icons_config 0 #define style_namelistgad_config 0 #define paned_userlist_config 0 /* XXX xchat def: 1 */ #define style_inputbox_config 0 /* XXX xchat commented def: 1 */ /* ekg2-core var */ #define config_timestamp_show 1 void ui_gtk_init(void); void ui_gtk_window_switch(int id); void ui_gtk_window_new(const char *target, int new_id); void ui_gtk_window_kill(struct window *w, int quiet); void ui_gtk_window_clear(struct window *w); void ui_gtk_binding_init(); void ui_gtk_foreach_window(int (*func)(struct window *)); void ui_gtk_foreach_window_data(int (*func)(struct window *, void *data), void *data); int key_handle_key_press(GtkWidget *wid, GdkEventKey *evt, window_t *sess); /* ui-maingui.c */ void mg_changui_new(window_t *sess, int tab, int focus); void fe_close_window(window_t *sess); #endif ekg-1.9~pre+r2855/src/ui-ncurses.c000066400000000000000000004274431174410337000166650ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2008 Wojtek Kaniewski * Wojtek Bojdoł * Paweł Maziarz * Piotr Kupisiewicz * Adam Wysocki * * Aspell support added by Piotr 'Deletek' Kupisiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * 21:56 <@Kooba> MASZ OKIENKA ALA IRSSI? * 21:56 <@Kooba> no to chlopie. * 21:56 <@Kooba> wywalam gaima. * 21:56 <@Kooba> bo taki ekg obsluguje dzwiek. * 21:56 <@Kooba> dcc * 21:56 <@bkU> JA CIE! * 21:56 <@Kooba> i lepiej wyszukuje. * 21:56 <@Kooba> i lepiej sie podrywa LASKI! * * 21:59 <@bkU> elluin, możesz napisać, tak jak w łańcuszkach szczęścia * 21:59 <@bkU> Hosse Pedro Alvaros z południowej Gwatemali * 21:59 <@bkU> przestał używać ekg * 21:59 <@bkU> i w ciągu 7 dni stracił wszystko * * 22:02 <@bkU> ekg może wszystko! * 22:02 <@bkU> ostatnio słyszałem przecieki, że w NASA używają właśnie ekg. */ #include "config.h" #include #include #include #include #include #ifdef HAVE_LIBGEN_H # include #else # include "../compat/dirname.h" #endif #ifndef HAVE_SCANDIR # include "../compat/scandir.h" #endif #include #include #include #include #include #include #include "commands.h" #include "libgadu.h" #include "mail.h" #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #ifdef WITH_ASPELL # include #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "userlist.h" #include "vars.h" #include "version.h" #include "xmalloc.h" #ifdef WITH_PYTHON # include "python.h" #endif /* nadpisujemy funkcję strncasecmp() odpowiednikiem z obsługą polskich znaków */ #define strncasecmp(x...) strncasecmp_pl(x) static void ui_ncurses_loop(); static void ui_ncurses_print(const char *target, int separate, const char *line); static void ui_ncurses_beep(); static int ui_ncurses_event(const char *event, ...); static void ui_ncurses_postinit(); static void ui_ncurses_deinit(); static void window_switch(int id); static void update_statusbar(int commit); static void binding_add(const char *key, const char *action, int internal, int quiet); static void binding_delete(const char *key, int quiet); static void binding_default(); static struct mouse_area_t *mouse_area_resize (const char *name, int y, int x); static struct mouse_area_t *mouse_area_move (const char *name, int y, int x); struct screen_line { int len; /* długość linii */ char *str; /* treść */ char *attr; /* atrybuty */ char *prompt_str; /* treść promptu */ char *prompt_attr; /* atrybuty promptu */ int prompt_len; /* długość promptu */ char *ts; /* timestamp */ int ts_len; /* długość timestampu */ int backlog; /* z której linii backlogu pochodzi? */ }; enum window_frame_t { WF_LEFT = 1, WF_TOP = 2, WF_RIGHT = 4, WF_BOTTOM = 8, WF_ALL = 15 }; struct window { WINDOW *window; /* okno okna */ int floating; /* czy pływające? */ int doodle; /* czy do gryzmolenia? */ int frames; /* informacje o ramkach */ int edge; /* okienko brzegowe */ int last_update; /* czas ostatniego uaktualnienia */ int nowrap; /* nie zawijamy linii */ int hide; /* ukrywamy, bo jest zbyt duże */ char *target; /* nick query albo inna nazwa albo NULL */ int id; /* numer okna */ int act; /* czy coś się zmieniło? */ int more; /* pojawiło się coś poza ekranem */ time_t first_act_time; /* timestamp zmiany act */ time_t last_act_time; /* timestamp ostatniej aktywności */ char *prompt; /* sformatowany prompt lub NULL */ int prompt_len; /* długość prompta lub 0 */ int left, top; /* pozycja (x, y) względem początku ekranu */ int width, height; /* wymiary okna */ int margin_left, margin_right, margin_top, margin_bottom; /* marginesy */ fstring_t *backlog; /* bufor z liniami */ int backlog_size; /* rozmiar backloga */ int redraw; /* trzeba przerysować przed wyświetleniem */ int start; /* od której linii zaczyna się wyświetlanie */ int lines_count; /* ilość linii ekranowych w backlogu */ struct screen_line *lines; /* linie ekranowe */ int overflow; /* ilość nadmiarowych linii w okienku */ int (*handle_redraw)(struct window *w); /* obsługa przerysowania zawartości okna */ }; struct format_data { char *name; /* %{nazwa} */ char *text; /* treść */ }; struct mouse_coords_t { int x, y; /* pozycja punktu na ekranie */ }; typedef void (*mouse_handler_t) (struct mouse_coords_t *, mmask_t); struct mouse_bevent_t { mmask_t bstate; /* stan buttonów zgodnie z MEVENT->bstate */ mouse_handler_t handler; /* handler dla tego stanu buttonów */ }; struct mouse_area_t { char *name; /* nazwa obszaru */ struct mouse_coords_t start; /* lewy gorny rog */ struct mouse_coords_t size; /* rozmiar */ struct mouse_coords_t end; /* prawy dolny rog (wypelniane przez funkcje obslugi) */ list_t bevents; /* handlery dla poszczególnych stanów buttonów */ }; struct mouse_statusbar_t { /* opis obszaru paska stanu */ char *act_str; /* lista aktywnych okien (string) */ /* [0] oznacza początek a [1] koniec (NIE rozmiar) */ struct mouse_coords_t time_c[2]; /* położenie zegarka */ struct mouse_coords_t uin_c[2]; /* położenie uinu: (uin/x) */ struct mouse_coords_t nick_c[2]; /* położenie nicka */ struct mouse_coords_t more_c[2]; /* położenie napisu "(more)" */ struct mouse_coords_t query_c[2]; /* położenie informacji na temat rozmówcy */ struct mouse_coords_t window_c[2]; /* położenie numerka aktualnego okna: (win/x:uin) */ struct mouse_coords_t act_c[2]; /* położenie listy aktywnych okien */ }; list_t mouse_areas; /* obszary w których mogą wystąpić zdarzenia myszy */ /* NULL-ujemy listę windows, żeby uniknąć problemów przy zwalnianiu w update */ struct mouse_statusbar_t mouse_statusbar = {NULL}; /* act_str */ struct mouse_statusbar_t mouse_statusbar_pending = {NULL}; /* ...i przed commitem */ WINDOW *status = NULL; /* okno stanu */ WINDOW *header = NULL; /* okno nagłówka */ static WINDOW *input = NULL; /* okno wpisywania tekstu */ static WINDOW *contacts = NULL; /* okno kontaktów */ #define HISTORY_MAX 1000 /* maksymalna ilość wpisów historii */ static char *history[HISTORY_MAX]; /* zapamiętane linie */ static int history_index = 0; /* offset w historii */ #define LINE_MAXLEN 1000 /* rozmiar linii */ static char *line = NULL; /* wskaźnik aktualnej linii */ static char *yanked = NULL; /* bufor z ostatnio wyciętym tekstem */ static char **lines = NULL; /* linie wpisywania wielolinijkowego */ static int line_start = 0; /* od którego znaku wyświetlamy? */ static int line_index = 0; /* na którym znaku jest kursor? */ static int lines_start = 0; /* od której linii wyświetlamy? */ static int lines_index = 0; /* w której linii jesteśmy? */ static char **completions = NULL; /* lista dopełnień */ static list_t windows = NULL; /* lista okien */ static struct window *window_current; /* wskaźnik na aktualne okno */ static int window_last_id = -1; /* numer ostatnio wybranego okna */ static int input_size = 1; /* rozmiar okna wpisywania tekstu */ static int ui_ncurses_debug = 0; /* debugowanie */ static int ui_ncurses_inited = 0; /* czy zainicjowano? */ static int ui_ncurses_beeping = 0; /* czy my własnie beepamy? */ static struct termios old_tio; int config_backlog_overlap = 0; /* liczba zachodzących linii przy przewijaniu */ int config_backlog_size = 1000; /* maksymalny rozmiar backloga */ int config_display_transparent = 1; /* czy chcemy przezroczyste tło? */ int config_contacts_size = 9; /* szerokość okna kontaktów */ int config_contacts = 2; /* czy ma być okno kontaktów */ char *config_contacts_options = NULL; /* opcje listy kontaktów */ char *config_contacts_groups = NULL; /* grupy listy kontaktów */ int config_beep_title = 0; /* czy beepamy w pasku tytułowym? */ static int contacts_margin = 1; static int contacts_edge = WF_RIGHT; static int contacts_frame = WF_LEFT; static int contacts_descr = 0; static int contacts_wrap = 0; static int contacts_order[7] = { 5, 0, 1, 6, 2, 3, -1 }; static int contacts_framecolor = 4; static int contacts_group_index = 0; static int contacts_count = 0; static int contacts_offset = 0; struct binding *binding_map[KEY_MAX + 1]; /* mapa bindowanych klawiszy */ struct binding *binding_map_meta[KEY_MAX + 1]; /* j.w. z altem */ static void window_kill(struct window *w, int quiet); static int window_backlog_split(struct window *w, int full, int removed); static void window_redraw(struct window *w); static void window_clear(struct window *w, int full); static void window_refresh(); static void binding_forward_page(const char *arg); static int contacts_update(struct window *w); static void mouse_statusbar_commit(void); #ifndef COLOR_DEFAULT # define COLOR_DEFAULT (-1) #endif #ifdef WITH_ASPELL # define ASPELLBADCHAR 5 // # define ASPELL_ALLOWED_CHARS "()[]',.`\"<>!?" AspellConfig *spell_config = NULL; AspellSpeller *spell_checker = NULL; static char *aspell_line; #endif /* * zamienia podany znak na mały; jeśli to możliwe * obsługuje polskie znaki */ static int tolower_pl(const unsigned char c) { switch (c) { case 161: // Ą return 177; case 198: // Ć return 230; case 202: // Ę return 234; case 163: // Ł return 179; case 209: // Ń return 241; case 211: // Ó return 243; case 166: // Ś return 182; case 175: // Ż return 191; case 172: // Ź return 188; default: // reszta return tolower(c); } } /* * strncasecmp_pl() * * porównuje dwa ciągi o określonej długości. * działa analogicznie do strncasecmp(), ale obsługuje * polskie znaki. */ int strncasecmp_pl(const char *cs, const char *ct, size_t count) { register char res = 0; while (count) { if ((res = tolower_pl(*cs) - tolower_pl(*ct++)) != 0 || !*cs++) break; count--; } return res; } /* * contacts_size() * * liczy szerokość okna z listą kontaktów. */ int contacts_size() { if (!config_contacts) return 0; if (config_contacts_size + 2 > (stdscr->_maxx + 1) / 2) return 0; return config_contacts_size + (contacts_frame) ? 1 : 0; } /* * ui_debug() * * wyświetla szybko sformatowany tekst w aktualnym oknie. do debugowania. */ #define ui_debug(x...) { \ char *ui_debug_tmp = saprintf("UI " x); \ ui_ncurses_print("__debug", 0, ui_debug_tmp); \ xfree(ui_debug_tmp); \ } /* * color_pair() * * zwraca numer COLOR_PAIR odpowiadającej danej parze atrybutów: kolorze * tekstu (plus pogrubienie) i kolorze tła. */ static int color_pair(int fg, int bold, int bg) { if (fg >= 8) { bold = 1; fg &= 7; } if (fg == COLOR_BLACK && bg == COLOR_BLACK) { fg = 7; } else if (fg == COLOR_WHITE && bg == COLOR_BLACK) { fg = 0; } if (!config_display_color) { if (bg != COLOR_BLACK) return A_REVERSE; else return A_NORMAL | ((bold) ? A_BOLD : 0); } return COLOR_PAIR(fg + 8 * bg) | ((bold) ? A_BOLD : 0); } /* * window_commit() * * zatwierdza wszystkie zmiany w buforach ncurses i wyświetla je na ekranie. */ void window_commit() { window_refresh(); if (header) wnoutrefresh(header); wnoutrefresh(status); mouse_statusbar_commit(); wnoutrefresh(input); doupdate(); } /* * window_backlog_add() * * dodaje do bufora okna. zakładamy dodawanie linii już podzielonych. * jeśli doda się do backloga linię zawierającą '\n', będzie źle. * * - w - wskaźnik na okno ekg * - str - linijka do dodania * * zwraca rozmiar dodanej linii w liniach ekranowych. */ int window_backlog_add(struct window *w, fstring_t str) { int i, removed = 0; if (!w) return 0; if (w->backlog_size == config_backlog_size) { fstring_t fs = w->backlog[w->backlog_size - 1]; int i; for (i = 0; i < w->lines_count; i++) { if (w->lines[i].backlog == w->backlog_size - 1) removed++; } xfree(fs->str); xfree(fs->attr); xfree(fs); w->backlog_size--; } else w->backlog = xrealloc(w->backlog, (w->backlog_size + 1) * sizeof(fstring_t)); memmove(&w->backlog[1], &w->backlog[0], w->backlog_size * sizeof(fstring_t)); w->backlog[0] = str; w->backlog_size++; for (i = 0; i < w->lines_count; i++) w->lines[i].backlog++; return window_backlog_split(w, 0, removed); } /* * window_backlog_split() * * dzieli linie tekstu w buforze na linie ekranowe. * * - w - okno do podzielenia * - full - czy robimy pełne uaktualnienie? * - removed - ile linii ekranowych z góry usunięto? * * zwraca rozmiar w liniach ekranowych ostatnio dodanej linii. */ int window_backlog_split(struct window *w, int full, int removed) { int i, res = 0, bottom = 0; if (!w) return 0; /* przy pełnym przebudowaniu ilości linii nie muszą się koniecznie * zgadzać, więc nie będziemy w stanie później stwierdzić czy jesteśmy * na końcu na podstawie ilości linii mieszczących się na ekranie. */ if (full && w->start == w->lines_count - w->height) bottom = 1; /* mamy usunąć coś z góry, bo wywalono linię z backloga. */ if (removed) { for (i = 0; i < removed && i < w->lines_count; i++) xfree(w->lines[i].ts); memmove(&w->lines[0], &w->lines[removed], sizeof(struct screen_line) * (w->lines_count - removed)); w->lines_count -= removed; } /* jeśli robimy pełne przebudowanie backloga, czyścimy wszystko */ if (full) { for (i = 0; i < w->lines_count; i++) xfree(w->lines[i].ts); w->lines_count = 0; xfree(w->lines); w->lines = NULL; } /* jeśli upgrade... jeśli pełne przebudowanie... */ for (i = (!full) ? 0 : (w->backlog_size - 1); i >= 0; i--) { struct screen_line *l; char *str, *attr; int j; time_t ts; str = w->backlog[i]->str + w->backlog[i]->prompt_len; attr = w->backlog[i]->attr + w->backlog[i]->prompt_len; ts = w->backlog[i]->ts; for (;;) { int word = 0, width; if (!i) res++; w->lines_count++; w->lines = xrealloc(w->lines, w->lines_count * sizeof(struct screen_line)); l = &w->lines[w->lines_count - 1]; l->str = str; l->attr = attr; l->len = strlen(str); l->ts = NULL; l->ts_len = 0; l->backlog = i; l->prompt_len = w->backlog[i]->prompt_len; if (!w->backlog[i]->prompt_empty) { l->prompt_str = w->backlog[i]->str; l->prompt_attr = w->backlog[i]->attr; } else { l->prompt_str = NULL; l->prompt_attr = NULL; } if (!w->floating && config_timestamp) { struct tm *tm = localtime(&ts); char buf[100]; strftime(buf, sizeof(buf), config_timestamp, tm); l->ts = xstrdup(buf); l->ts_len = strlen(l->ts); } width = w->width - l->ts_len - l->prompt_len - w->margin_left - w->margin_right; if ((w->frames & WF_LEFT)) width -= 1; if ((w->frames & WF_RIGHT)) width -= 1; if (l->len < width) break; for (j = 0, word = 0; j < l->len; j++) { if (str[j] == ' ' && !w->nowrap) word = j + 1; if (j == width) { l->len = (word) ? word : width; if (str[j] == ' ') { l->len--; str++; attr++; } break; } } if (w->nowrap) { while (*str) { str++; attr++; } break; } str += l->len; attr += l->len; if (!str[0]) break; } } if (bottom) { w->start = w->lines_count - w->height; if (w->start < 0) w->start = 0; } if (full) { if (window_current && window_current->id == w->id) window_redraw(w); else w->redraw = 1; } return res; } /* * window_resize() * * dostosowuje rozmiar okien do rozmiaru ekranu, przesuwając odpowiednio * wyświetlaną zawartość. */ void window_resize() { int left, right, top, bottom, width, height; list_t l; left = 0; right = stdscr->_maxx + 1; top = config_header_size; bottom = stdscr->_maxy + 1 - input_size - config_statusbar_size; width = right - left; height = bottom - top; if (width < 1) width = 1; if (height < 1) height = 1; for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->edge) continue; w->hide = 0; if ((w->edge & WF_LEFT)) { if (w->width * 2 > width) w->hide = 1; else { w->left = left; w->top = top; w->height = height; w->hide = 0; width -= w->width; left += w->width; } } if ((w->edge & WF_RIGHT)) { if (w->width * 2 > width) w->hide = 1; else { w->left = right - w->width; w->top = top; w->height = height; width -= w->width; right -= w->width; } } if ((w->edge & WF_TOP)) { if (w->height * 2 > height) w->hide = 1; else { w->left = left; w->top = top; w->width = width; height -= w->height; top += w->height; } } if ((w->edge & WF_BOTTOM)) { if (w->height * 2 > height) w->hide = 1; else { w->left = left; w->top = bottom - w->height; w->width = width; height -= w->height; bottom -= w->height; } } wresize(w->window, w->height, w->width); mvwin(w->window, w->top, w->left); /* ui_debug("edge window id=%d resized to (%d,%d,%d,%d)\n", w->id, w->left, w->top, w->width, w->height); */ w->redraw = 1; } for (l = windows; l; l = l->next) { struct window *w = l->data; int delta; if (w->floating) continue; delta = height - w->height; if (w->lines_count - w->start == w->height) { w->start -= delta; if (delta < 0) { if (w->start > w->lines_count) w->start = w->lines_count; } else { if (w->start < 0) w->start = 0; } } if (w->overflow > height) w->overflow = height; w->height = height; if (w->height < 1) w->height = 1; if (w->width != width && !w->doodle) { w->width = width; window_backlog_split(w, 1, 0); } w->width = width; wresize(w->window, w->height, w->width); w->top = top; w->left = left; if (w->left < 0) w->left = 0; if (w->left > stdscr->_maxx) w->left = stdscr->_maxx; if (w->top < 0) w->top = 0; if (w->top > stdscr->_maxy) w->top = stdscr->_maxy; mvwin(w->window, w->top, w->left); /* ui_debug("normal window id=%d resized to (%d,%d,%d,%d)\n", w->id, w->left, w->top, w->width, w->height); */ if (w->overflow) w->start = w->lines_count - w->height + w->overflow; w->redraw = 1; } if (window_current) { mouse_area_resize("window_current", window_current->window->_maxy, window_current->window->_maxx); mouse_area_move("window_current", window_current->window->_begy, window_current->window->_begx); } ui_screen_width = width; ui_screen_height = height; } /* * window_redraw() * * przerysowuje zawartość okienka. * * - w - okno */ void window_redraw(struct window *w) { int x, y, left = w->margin_left, top = w->margin_top, height = w->height - w->margin_top - w->margin_bottom; if (w->doodle) { w->redraw = 0; return; } if (w->handle_redraw) { /* handler może sam narysować wszystko, wtedy zwraca -1. * może też tylko uaktualnić zawartość okna, wtedy zwraca * 0 i rysowaniem zajmuje się ta funkcja. */ if (w->handle_redraw(w) == -1) return; } werase(w->window); wattrset(w->window, color_pair(contacts_framecolor, 0, COLOR_BLACK)); if (w->floating) { if ((w->frames & WF_LEFT)) { left++; for (y = 0; y < w->height; y++) mvwaddch(w->window, y, w->margin_left, ACS_VLINE); } if ((w->frames & WF_RIGHT)) { for (y = 0; y < w->height; y++) mvwaddch(w->window, y, w->width - 1 - w->margin_right, ACS_VLINE); } if ((w->frames & WF_TOP)) { top++; height--; for (x = 0; x < w->width; x++) mvwaddch(w->window, w->margin_top, x, ACS_HLINE); } if ((w->frames & WF_BOTTOM)) { height--; for (x = 0; x < w->width; x++) mvwaddch(w->window, w->height - 1 - w->margin_bottom, x, ACS_HLINE); } if ((w->frames & WF_LEFT) && (w->frames & WF_TOP)) mvwaddch(w->window, 0, 0, ACS_ULCORNER); if ((w->frames & WF_RIGHT) && (w->frames & WF_TOP)) mvwaddch(w->window, 0, w->width - 1, ACS_URCORNER); if ((w->frames & WF_LEFT) && (w->frames & WF_BOTTOM)) mvwaddch(w->window, w->height - 1, 0, ACS_LLCORNER); if ((w->frames & WF_RIGHT) && (w->frames & WF_BOTTOM)) mvwaddch(w->window, w->height - 1, w->width - 1, ACS_LRCORNER); } if (w->start < 0) w->start = 0; for (y = 0; y < height && w->start + y < w->lines_count; y++) { struct screen_line *l = &w->lines[w->start + y]; wattrset(w->window, A_NORMAL); for (x = 0; l->ts && x < l->ts_len; x++) mvwaddch(w->window, top + y, left + x, (unsigned char) l->ts[x]); for (x = 0; x < l->prompt_len + l->len; x++) { int attr = A_NORMAL; unsigned char ch, chattr; if (x < l->prompt_len) { if (!l->prompt_str) continue; ch = l->prompt_str[x]; chattr = l->prompt_attr[x]; } else { ch = l->str[x - l->prompt_len]; chattr = l->attr[x - l->prompt_len]; } if ((chattr & 64)) attr |= A_BOLD; if (!(chattr & 128)) attr |= color_pair(chattr & 7, 0, COLOR_BLACK); if (ch == 10) { ch = '|'; attr |= color_pair(COLOR_BLACK, 1, COLOR_BLACK); } if (ch < 32) { ch += 64; attr |= A_REVERSE; } if (ch > 127 && ch < 160) { ch = '?'; attr |= A_REVERSE; } wattrset(w->window, attr); mvwaddch(w->window, top + y, left + x + l->ts_len, ch); } } w->redraw = 0; } /* * window_clear() * * czyści zawartość okna. */ static void window_clear(struct window *w, int full) { if (!full) { w->start = w->lines_count; w->redraw = 1; w->overflow = w->height; return; } if (w->backlog) { int i; for (i = 0; i < w->backlog_size; i++) { xfree(w->backlog[i]->str); xfree(w->backlog[i]->attr); xfree(w->backlog[i]); } xfree(w->backlog); w->backlog = NULL; w->backlog_size = 0; } if (w->lines) { int i; for (i = 0; i < w->lines_count; i++) xfree(w->lines[i].ts); xfree(w->lines); w->lines = NULL; w->lines_count = 0; } w->start = 0; w->redraw = 1; w->more = 0; } /* * window_find() * * szuka okna o podanym celu. zwraca strukturę opisującą je. */ static struct window *window_find(const char *target) { list_t l; int current = ((target) ? !strcasecmp(target, "$") || !strcasecmp(target, "__current") : 0); int debug = ((target) ? !strcasecmp(target, "__debug") : 0); int status = ((target) ? !strcasecmp(target, "__status") : 0); struct userlist *u = NULL; if (!target || current) { if (window_current->id) return window_current; else status = 1; } if (target) u = userlist_find(get_uin(target), NULL); for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->id && debug) return w; if (w->id == 1 && status) return w; if (w->target && target) { if (!strcasecmp(target, w->target)) return w; if (u && u->display && !strcasecmp(u->display, w->target)) return w; if (u && !strcasecmp(itoa(u->uin), w->target)) return w; } } return NULL; } /* * window_floating_update() * * uaktualnia zawartość pływającego okna o id == n * lub wszystkich okienek, gdy n == 0. */ static void window_floating_update(int n) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data, *tmp; if (n && (w->id != n)) continue; if (!w->floating) continue; /* jeśli ma własną obsługę odświeżania, nie ruszamy */ if (w->handle_redraw) continue; if (w->last_update == time(NULL)) continue; w->last_update = time(NULL); window_clear(w, 1); tmp = window_current; window_current = w; command_exec(w->target, w->target, 0); window_current = tmp; window_redraw(w); } } /* * window_refresh() * * wnoutrefresh()uje aktualnie wyświetlane okienko. */ static void window_refresh() { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->floating || window_current->id != w->id) continue; if (w->redraw) window_redraw(w); if (!w->hide) wnoutrefresh(w->window); } for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->floating || w->hide) continue; if (w->handle_redraw) window_redraw(w); else window_floating_update(w->id); touchwin(w->window); wnoutrefresh(w->window); } mvwin(status, stdscr->_maxy + 1 - input_size - config_statusbar_size, 0); mouse_area_move("status", stdscr->_maxy + 1 - input_size - config_statusbar_size, 0); wresize(input, input_size, input->_maxx + 1); mvwin(input, stdscr->_maxy - input_size + 1, 0); } /* * window_switch() * * przełącza do podanego okna. */ static void window_switch(int id) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (id != w->id || w->floating) continue; if (id != window_current->id) window_last_id = window_current->id; window_current = w; w->act = 0; if (w->redraw) window_redraw(w); touchwin(w->window); update_statusbar(0); window_commit(); break; } } /* * window_new_compare() * * do sortowania okienek. */ static int window_new_compare(void *data1, void *data2) { struct window *a = data1, *b = data2; if (!a || !b) return 0; return a->id - b->id; } /* * window_new() * * tworzy nowe okno o podanej nazwie i id. */ static struct window *window_new(const char *target, int new_id) { struct window w, *result = NULL; int id = 1, done = 0; list_t l; struct userlist *u = NULL; if (target) { struct window *w = window_find(target); if (w) return w; u = userlist_find(0, target); if (!strcmp(target, "$")) return window_current; } if (target && *target == '*' && !u) id = 100; while (!done) { done = 1; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id == id) { done = 0; id++; break; } } } if (new_id != 0) id = new_id; /* okno z debug'iem */ if (id == -1) id = 0; memset(&w, 0, sizeof(w)); w.id = id; w.last_act_time = time(NULL); /* domyślne rozmiary zostaną dostosowane przez window_resize() */ w.top = 0; w.left = 0; w.width = 1; w.height = 1; if (target) { if (!strcmp(target, "__contacts")) { int size = config_contacts_size + contacts_margin + ((contacts_frame) ? 1 : 0); switch (contacts_edge) { case WF_LEFT: w.width = size; w.margin_right = contacts_margin; break; case WF_RIGHT: w.width = size; w.margin_left = contacts_margin; break; case WF_TOP: w.height = size; w.margin_bottom = contacts_margin; break; case WF_BOTTOM: w.height = size; w.margin_top = contacts_margin; break; } w.floating = 1; w.edge = contacts_edge; w.frames = contacts_frame; w.handle_redraw = contacts_update; w.target = xstrdup(target); w.nowrap = !contacts_wrap; } if (*target == '+' && !u) { w.doodle = 1; w.target = xstrdup(target + 1); } if (*target == '*' && !u) { const char *tmp = strchr(target, '/'); char **argv, **arg; w.floating = 1; if (!tmp) tmp = ""; w.target = xstrdup(tmp); argv = arg = array_make(target + 1, ",", 5, 0, 0); w.width = 10; /* domyślne wymiary */ w.height = 5; if (*arg) w.left = atoi(*arg++); if (*arg) w.top = atoi(*arg++); if (*arg) w.width = atoi(*arg++); if (*arg) w.height = atoi(*arg++); if (*arg && *arg[0] != '/') w.frames = atoi(*arg); array_free(argv); if (w.left > stdscr->_maxx) w.left = stdscr->_maxx; if (w.top > stdscr->_maxy) w.top = stdscr->_maxy; if (w.left + w.width > stdscr->_maxx) w.width = stdscr->_maxx + 1 - w.left; if (w.top + w.height > stdscr->_maxy) w.height = stdscr->_maxy + 1 - w.top; } if (!w.target) { w.target = xstrdup(target); w.prompt = format_string(format_find("ncurses_prompt_query"), target); w.prompt_len = strlen(w.prompt); } } if (!target) { const char *f = format_find("ncurses_prompt_none"); if (strcmp(f, "")) { w.prompt = xstrdup(f); w.prompt_len = strlen(w.prompt); } } w.window = newwin(w.height, w.width, w.top, w.left); result = list_add_sorted(&windows, &w, sizeof(w), window_new_compare); window_resize(); return result; } /* * ui_ncurses_print() * * wyświetla w podanym okienku, co trzeba. */ static void ui_ncurses_print(const char *target, int separate, const char *line) { struct window *w; fstring_t fs; list_t l; int count = 0, bottom = 0, prev_count; char *lines, *lines_save, *line2; string_t speech = NULL; time_t cur_time; switch (config_make_window & 3) { case 1: if ((w = window_find(target))) goto crap; if (!separate) w = window_find("__status"); for (l = windows; l; l = l->next) { struct window *w = l->data; if (separate && !w->target && w->id > 1) { w->target = xstrdup(target); xfree(w->prompt); w->prompt = format_string(format_find("ncurses_prompt_query"), target); w->prompt_len = strlen(w->prompt); print("window_id_query_started", itoa(w->id), target); print_window(target, 1, "query_started", target); print_window(target, 1, "query_started_window", target); if (get_uin(target) && !(ignored_check(get_uin(target)) & IGNORE_EVENTS)) event_check(EVENT_QUERY, get_uin(target), target); break; } } case 2: if (!(w = window_find(target))) { if (!separate) w = window_find("__status"); else { w = window_new(target, 0); print("window_id_query_started", itoa(w->id), target); print_window(target, 1, "query_started", target); print_window(target, 1, "query_started_window", target); if (get_uin(target) && !(ignored_check(get_uin(target)) & IGNORE_EVENTS)) event_check(EVENT_QUERY, get_uin(target), target); } } crap: if (!config_display_crap && target && !strcmp(target, "__current")) w = window_find("__status"); break; default: /* jeśli nie ma okna, rzuć do statusowego. */ if (!(w = window_find(target))) w = window_find("__status"); } /* albo zaczynamy, albo kończymy i nie ma okienka żadnego */ if (!w) return; cur_time = time(NULL); if (config_speech_app) speech = string_init(NULL); if (w->start == w->lines_count - w->height || (w->start == 0 && w->lines_count <= w->height)) bottom = 1; prev_count = w->lines_count; if (config_display_daychanges) { int day_win, day_cur; day_win = localtime(&w->last_act_time)->tm_yday; day_cur = localtime(&cur_time)->tm_yday; if (cur_time > w->last_act_time && day_win != day_cur) { struct tm *tm; char *tmp, *fmt, *tmp2; char str_win[12], str_cur[12]; fmt = (config_datestamp) ? config_datestamp : "%Y-%m-%d"; tm = localtime(&w->last_act_time); strftime (str_win, sizeof(str_win), fmt, tm); tm = localtime(&cur_time); strftime (str_cur, sizeof(str_cur), fmt, tm); tmp = format_string(format_find("window_day_changed"), str_win, str_cur); if ((tmp2 = strchr(tmp, '\n'))) *tmp2 = 0; fs = reformat_string(tmp); fs->ts = cur_time; if (config_speech_app) { string_append(speech, fs->str); string_append_c(speech, '\n'); } count += window_backlog_add(w, fs); xfree(tmp); } } w->last_act_time = cur_time; if (w != window_current && !w->floating) { // xxx brzydki hack - rozpoznawanie, czy okno jest rozmową, // po separate // w->act == 0 - brak aktywności // w->act == 1 - aktywność mała // w->act == 2 - aktywność duża // w->act == 0, separate == 0 -> w->act = 1, aktualizujemy czas // w->act == 0, separate == 1 -> w->act = 2, aktualizujemy czas // w->act == 1, separate == 0 -> no-op // w->act == 1, separate == 1 -> w->act = 2, aktualizujemy czas // w->act == 2 -> no-op switch (w->act) { case 0: w->act = separate ? 2 : 1; w->first_act_time = w->last_act_time; break; case 1: if (separate) { w->act = 2; w->first_act_time = w->last_act_time; } break; default: break; } if (!command_processing) update_statusbar(0); } /* XXX wyrzucić dzielenie na linie z ui do ekg */ lines = lines_save = xstrdup(line); while ((line2 = get_line(&lines))) { fs = reformat_string(line2); fs->ts = cur_time; if (config_speech_app) { string_append(speech, fs->str); string_append_c(speech, '\n'); } count += window_backlog_add(w, fs); } xfree(lines_save); if (w->overflow) { w->overflow -= count; if (w->overflow < 0) { bottom = 1; w->overflow = 0; } } if (bottom) w->start = w->lines_count - w->height; else { if (w->backlog_size == config_backlog_size) w->start -= count - (w->lines_count - prev_count); } if (w->start < 0) w->start = 0; if (w->start < w->lines_count - w->height) w->more = 1; if (!w->floating) { window_redraw(w); if (!command_processing) window_commit(); } if (config_speech_app && !w->floating && w->id) say_it(speech->str); string_free(speech, 1); } /* * contacts_update() * * uaktualnia okno listy kontaktów. */ static int contacts_update(struct window *w) { struct { int status1, status2; char *format, *format_descr, *format_descr_full, *format_header, *format_footer; } table[7] = { { GG_STATUS_AVAIL, GG_STATUS_AVAIL_DESCR, "contacts_avail", "contacts_avail_descr", "contacts_avail_descr_full", "contacts_avail_header", "contacts_avail_footer" }, { GG_STATUS_BUSY, GG_STATUS_BUSY_DESCR, "contacts_busy", "contacts_busy_descr", "contacts_busy_descr_full", "contacts_busy_header", "contacts_busy_footer" }, { GG_STATUS_INVISIBLE, GG_STATUS_INVISIBLE_DESCR, "contacts_invisible", "contacts_invisible_descr", "contacts_invisible_descr_full", "contacts_invisible_header", "contacts_invisible_footer" }, { GG_STATUS_BLOCKED, -1, "contacts_blocking", "contacts_blocking", "contacts_blocking", "contacts_blocking_header", "contacts_blocking_footer" }, { GG_STATUS_NOT_AVAIL, GG_STATUS_NOT_AVAIL_DESCR, "contacts_not_avail", "contacts_not_avail_descr", "contacts_not_avail_descr_full", "contacts_not_avail_header", "contacts_not_avail_footer" }, { GG_STATUS_FFC, GG_STATUS_FFC_DESCR, "contacts_ffc", "contacts_ffc_descr", "contacts_ffc_descr_full", "contacts_ffc_header", "contacts_ffc_footer" }, { GG_STATUS_DND, GG_STATUS_DND_DESCR, "contacts_dnd", "contacts_dnd_descr", "contacts_dnd_descr_full", "contacts_dnd_header", "contacts_dnd_footer" }, }; const char *header = NULL, *footer = NULL; char *group = NULL; int j; int offset = contacts_offset; if (!w) { list_t l; for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->target && !strcmp(v->target, "__contacts")) { w = v; break; } } if (!w) return -1; } window_clear(w, 1); if (config_contacts_groups) { char **groups = array_make(config_contacts_groups, ", ", 0, 1, 0); if (contacts_group_index > array_count(groups)) contacts_group_index = 0; if (contacts_group_index > 0) { group = groups[contacts_group_index - 1]; if (*group == '@') group++; group = xstrdup(group); header = format_find("contacts_header_group"); footer = format_find("contacts_footer_group"); } array_free(groups); } if (!header || !footer) { header = format_find("contacts_header"); footer = format_find("contacts_footer"); } if (strcmp(header, "")) { char *tmp = format_string(header, group); window_backlog_add(w, reformat_string(tmp)); xfree(tmp); } contacts_count = 0; for (j = 0; j < 7; j++) { const char *header, *footer; int i = contacts_order[j], count; list_t l; if (i < 0 || i > 6) continue; header = format_find(table[i].format_header); footer = format_find(table[i].format_footer); count = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; const char *format; char *line; if ((u->status != table[i].status1 && u->status != table[i].status2) || !u->display || !u->uin) continue; if (ignored_check(u->uin) & IGNORE_DISPLAY) continue; if (group && !group_member(u, group)) continue; if (!count && strcmp(header, "")) { char *tmp = format_string(header); window_backlog_add(w, reformat_string(tmp)); xfree(tmp); } contacts_count++; if (offset) { offset--; continue; } if (GG_S_D(u->status) && contacts_descr) format = table[i].format_descr_full; else if (GG_S_D(u->status) && !contacts_descr) format = table[i].format_descr; else format = table[i].format; line = format_string(format_find(format), u->display, u->descr); window_backlog_add(w, reformat_string(line)); xfree(line); count++; } if (count && strcmp(footer, "")) { char *tmp = format_string(footer); window_backlog_add(w, reformat_string(tmp)); xfree(tmp); } } if (strcmp(footer, "")) { char *tmp = format_string(footer, group); window_backlog_add(w, reformat_string(tmp)); xfree(tmp); } xfree(group); w->redraw = 1; return 0; } /* * contacts_changed() * * wywoływane przy zmianach rozmiaru i włączeniu klienta. */ void contacts_changed() { struct window *w = NULL; list_t l; if (config_contacts_size < 0) config_contacts_size = 0; if (config_contacts_size == 0) config_contacts = 0; if (config_contacts_size > 1000) config_contacts_size = 1000; contacts_margin = 1; contacts_edge = WF_RIGHT; contacts_frame = WF_LEFT; contacts_order[0] = 5; contacts_order[1] = 0; contacts_order[2] = 1; contacts_order[3] = 6; contacts_order[4] = 2; contacts_order[5] = 3; contacts_order[6] = -1; contacts_wrap = 0; contacts_descr = 0; contacts_offset = 0; if (config_contacts_options) { char **args = array_make(config_contacts_options, " \t,", 0, 1, 1); int i; for (i = 0; args[i]; i++) { if (!strcasecmp(args[i], "left")) { contacts_edge = WF_LEFT; if (contacts_frame) contacts_frame = WF_RIGHT; } if (!strcasecmp(args[i], "right")) { contacts_edge = WF_RIGHT; if (contacts_frame) contacts_frame = WF_LEFT; } if (!strcasecmp(args[i], "top")) { contacts_edge = WF_TOP; if (contacts_frame) contacts_frame = WF_BOTTOM; } if (!strcasecmp(args[i], "bottom")) { contacts_edge = WF_BOTTOM; if (contacts_frame) contacts_frame = WF_TOP; } if (!strcasecmp(args[i], "noframe")) contacts_frame = 0; if (!strcasecmp(args[i], "frame")) { switch (contacts_edge) { case WF_TOP: contacts_frame = WF_BOTTOM; break; case WF_BOTTOM: contacts_frame = WF_TOP; break; case WF_LEFT: contacts_frame = WF_RIGHT; break; case WF_RIGHT: contacts_frame = WF_LEFT; break; } } if (!strncasecmp(args[i], "margin=", 7)) { contacts_margin = atoi(args[i] + 7); if (contacts_margin > 10) contacts_margin = 10; if (contacts_margin < 0) contacts_margin = 0; } if (!strcasecmp(args[i], "nomargin")) contacts_margin = 0; if (!strcasecmp(args[i], "wrap")) contacts_wrap = 1; if (!strcasecmp(args[i], "nowrap")) contacts_wrap = 0; if (!strcasecmp(args[i], "descr")) contacts_descr = 1; if (!strcasecmp(args[i], "nodescr")) contacts_descr = 0; if (!strncasecmp(args[i], "framecolor=", 11)) if (args[i][11]) sscanf(args[i] + 11, "%d", &contacts_framecolor); if (!strncasecmp(args[i], "order=", 6)) { int j; contacts_order[0] = -1; contacts_order[1] = -1; contacts_order[2] = -1; contacts_order[3] = -1; contacts_order[4] = -1; contacts_order[5] = -1; contacts_order[6] = -1; for (j = 0; args[i][j + 6] && j < 7; j++) if (args[i][j + 6] >= '0' && args[i][j + 6] <= '6') contacts_order[j] = args[i][j + 6] - '0'; } } if (contacts_margin < 0) contacts_margin = 0; array_free(args); } for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->target && !strcmp(v->target, "__contacts")) { w = v; break; } } if (w) { window_kill(w, 1); w = NULL; } if (config_contacts && !w) window_new("__contacts", 1000); contacts_update(NULL); window_commit(); } /* * update_header() * * uaktualnia nagłówek okna i wyświetla go ponownie. * * - commit - czy wyświetlić od razu? */ static void update_header(int commit) { int y; if (!header) return; wattrset(header, color_pair(COLOR_WHITE, 0, COLOR_BLUE)); for (y = 0; y < config_header_size; y++) { int x; wmove(header, y, 0); for (x = 0; x <= status->_maxx; x++) waddch(header, ' '); } if (commit) window_commit(); } /* * window_printat() * * wyświetla dany tekst w danym miejscu okna. * * - w - okno ncurses, do którego piszemy * - x, y - współrzędne, od których zaczynamy * - format - co mamy wyświetlić * - data - dane do podstawienia w formatach * - fgcolor - domyślny kolor tekstu * - bold - domyślne pogrubienie * - bgcolor - domyślny kolor tła * - status - czy to pasek stanu albo nagłówek okna? * * zwraca ilość dopisanych znaków. */ int window_printat(WINDOW *w, int x, int y, const char *format_, void *data_, int fgcolor, int bold, int bgcolor, int status) { int orig_x = x; int backup_display_color = config_display_color; char *format = (char*) format_; const char *p; struct format_data *data = data_; if (!config_display_pl_chars) { format = xstrdup(format); iso_to_ascii((unsigned char*) format); } p = format; if (status && config_display_color == 2) config_display_color = 0; if (status && x == 0) { int i; wattrset(w, color_pair(fgcolor, 0, bgcolor)); wmove(w, y, 0); for (i = 0; i <= w->_maxx; i++) waddch(w, ' '); } wmove(w, y, x); while (*p && *p != '}' && x <= w->_maxx) { int i, nest; if (*p != '%') { waddch(w, (unsigned char) *p); p++; x++; continue; } p++; if (!*p) break; #define __fgcolor(x,y,z) \ case x: fgcolor = z; bold = 0; break; \ case y: fgcolor = z; bold = 1; break; #define __bgcolor(x,y) \ case x: bgcolor = y; break; if (*p != '{') { switch (*p) { __fgcolor('k', 'K', COLOR_BLACK); __fgcolor('r', 'R', COLOR_RED); __fgcolor('g', 'G', COLOR_GREEN); __fgcolor('y', 'Y', COLOR_YELLOW); __fgcolor('b', 'B', COLOR_BLUE); __fgcolor('m', 'M', COLOR_MAGENTA); __fgcolor('c', 'C', COLOR_CYAN); __fgcolor('w', 'W', COLOR_WHITE); __bgcolor('l', COLOR_BLACK); __bgcolor('s', COLOR_RED); __bgcolor('h', COLOR_GREEN); __bgcolor('z', COLOR_YELLOW); __bgcolor('e', COLOR_BLUE); __bgcolor('q', COLOR_MAGENTA); __bgcolor('d', COLOR_CYAN); __bgcolor('x', COLOR_WHITE); case 'n': bgcolor = COLOR_BLUE; fgcolor = COLOR_WHITE; bold = 0; break; case '|': while (x <= w->_maxx) { waddch(w, ' '); x++; } break; case '}': waddch(w, '}'); p++; x++; break; } p++; wattrset(w, color_pair(fgcolor, bold, bgcolor)); continue; } if (*p != '{' && !config_display_color) continue; p++; if (!*p) break; for (i = 0; data && data[i].name; i++) { int len; if (!data[i].text) continue; len = strlen(data[i].name); if (!strncmp(p, data[i].name, len) && p[len] == '}') { /* pozwolić wszędzie? */ int percent_ok = !strcmp(data[i].name, "activity"); char *text = data[i].text; int j; if (!config_display_pl_chars) { text = xstrdup(text); iso_to_ascii((unsigned char*) text); } for (j = 0; text && text[j]; j++) { if (text[j] == 10) { wattrset(w, color_pair(COLOR_BLACK, 1, bgcolor)); waddch(w, '|'); wattrset(w, color_pair(fgcolor, bold, bgcolor)); x++; } else if (text[j] == '%' && percent_ok) { switch (text[++j]) { __fgcolor('k', 'K', COLOR_BLACK); __fgcolor('r', 'R', COLOR_RED); __fgcolor('g', 'G', COLOR_GREEN); __fgcolor('y', 'Y', COLOR_YELLOW); __fgcolor('b', 'B', COLOR_BLUE); __fgcolor('m', 'M', COLOR_MAGENTA); __fgcolor('c', 'C', COLOR_CYAN); __fgcolor('w', 'W', COLOR_WHITE); __bgcolor('l', COLOR_BLACK); __bgcolor('s', COLOR_RED); __bgcolor('h', COLOR_GREEN); __bgcolor('z', COLOR_YELLOW); __bgcolor('e', COLOR_BLUE); __bgcolor('q', COLOR_MAGENTA); __bgcolor('d', COLOR_CYAN); __bgcolor('x', COLOR_WHITE); case 'n': bgcolor = COLOR_BLUE; fgcolor = COLOR_WHITE; bold = 0; break; } wattrset(w, color_pair(fgcolor, bold, bgcolor)); } else { waddch(w, (unsigned char) text[j]); x++; } } p += len; if (!config_display_pl_chars) xfree(text); goto next; } } #undef __fgcolor #undef __bgcolor if (*p == '?') { int neg = 0; p++; if (!*p) break; if (*p == '!') { neg = 1; p++; } for (i = 0; data && data[i].name; i++) { int len, matched = ((data[i].text) ? 1 : 0); if (neg) matched = !matched; len = strlen(data[i].name); if (!strncmp(p, data[i].name, len) && p[len] == ' ') { p += len + 1; if (matched) x += window_printat(w, x, y, p, data, fgcolor, bold, bgcolor, status); goto next; } } goto next; } next: /* uciekamy z naszego poziomu zagnieżdżenia */ nest = 1; while (*p && nest) { if (*p == '}') nest--; if (*p == '{') nest++; p++; } } config_display_color = backup_display_color; if (!config_display_pl_chars) xfree(format); return x - orig_x; } /* * mouse_statusbar_update() * * aktualizuje strukturę mouse_statusbar_pending zgodnie z tym, co zostało * umieszczone na pasku stanu. korzysta mniej więcej z tego samego kodu, * co window_printat(), ale bez przeróbek window_printat() nie dało się * tego zrobić ładniej. * * zmiany zostaną permanentnie wprowadzone po wywołaniu mouse_statusbar_commit() * (jest wywoływane z window_commit()). * * UWAGA: nie można w tej funkcji używać gg_debug(), bo gg_debug() zmienia * statusbar i wychodzi z tego urocza pętelka :) * * - parametry jak dla window_printat() * - recurse: czy zostaliśmy wywołani rekurencyjnie? */ static int mouse_statusbar_update (int x, int y, const char *format_, const void *data_, int recurse) { int orig_x = x; char *format = (char*) format_; const char *p; const struct format_data *data = data_; p = format; if (!recurse) { #define __clear_coords(c) { \ mouse_statusbar_pending.c[0].x = mouse_statusbar_pending.c[0].y = -1; \ mouse_statusbar_pending.c[1].x = mouse_statusbar_pending.c[1].y = -1; \ } __clear_coords(time_c); __clear_coords(uin_c); __clear_coords(nick_c); __clear_coords(more_c); __clear_coords(query_c); __clear_coords(window_c); __clear_coords(act_c); #undef __clear_coords if (mouse_statusbar_pending.act_str) { xfree(mouse_statusbar_pending.act_str); mouse_statusbar_pending.act_str = NULL; } } while (p && *p && *p != '}' && x <= status->_maxx) { int i, nest; if (*p != '%') { p++; x++; continue; } p++; if (!*p) break; if (*p != '{') { switch (*p) { case '|': while (x <= status->_maxx) x++; break; case '}': p++; x++; break; default: break; } p++; continue; } if (*p != '{' && (!config_display_color || config_display_color == 2)) continue; p++; if (!*p) break; for (i = 0; data && data[i].name; i++) { int len; if (!data[i].text) continue; len = strlen(data[i].name); if (!strncmp(p, data[i].name, len) && p[len] == '}') { struct mouse_coords_t *cur; if (!strcmp(data[i].name, "time")) cur = mouse_statusbar_pending.time_c; else if (!strcmp(data[i].name, "uin")) cur = mouse_statusbar_pending.uin_c; else if (!strcmp(data[i].name, "nick")) cur = mouse_statusbar_pending.nick_c; else if (!strcmp(data[i].name, "more")) cur = mouse_statusbar_pending.more_c; else if (!strcmp(data[i].name, "query")) cur = mouse_statusbar_pending.query_c; else if (!strcmp(data[i].name, "window")) cur = mouse_statusbar_pending.window_c; else if (!strcmp(data[i].name, "activity")) { cur = mouse_statusbar_pending.act_c; mouse_statusbar_pending.act_str = xstrdup(data[i].text); } else { x += strlen(data[i].text); p += len; goto next; } cur[0].x = x; cur[0].y = cur[1].y = 0; x += strlen(data[i].text); cur[1].x = x - 1; p += len; goto next; } } if (*p == '?') { int neg = 0; p++; if (!*p) break; if (*p == '!') { neg = 1; p++; } for (i = 0; data && data[i].name; i++) { int len, matched = ((data[i].text) ? 1 : 0); if (neg) matched = !matched; len = strlen(data[i].name); if (!strncmp(p, data[i].name, len) && p[len] == ' ') { p += len + 1; if (matched) x += mouse_statusbar_update(x, y, p, data, 1); goto next; } } goto next; } next: /* uciekamy z naszego poziomu zagnieżdżenia */ nest = 1; while (*p && nest) { if (*p == '}') nest--; if (*p == '{') nest++; p++; } } return x - orig_x; } /* * mouse_statusbar_commit() * * ostatecznie zatwierdza zmiany zrobione w mouse_statusbar_update(). */ static void mouse_statusbar_commit (void) { if (mouse_statusbar.act_str) xfree(mouse_statusbar.act_str); memcpy (&mouse_statusbar, &mouse_statusbar_pending, sizeof(mouse_statusbar)); mouse_statusbar.act_str = xstrdup(mouse_statusbar_pending.act_str); } /* * update_statusbar() * * uaktualnia pasek stanu i wyświetla go ponownie. * * - commit - czy wyświetlić od razu? */ static void update_statusbar(int commit) { struct userlist *u = userlist_find(config_uin, NULL); struct userlist *q = userlist_find(str_to_uin(window_current->target), window_current->target); struct format_data *formats = NULL; int formats_count = 0, i, y; wattrset(status, color_pair(config_statusbar_fgcolor, 0, config_statusbar_bgcolor)); if (header) wattrset(header, color_pair(config_statusbar_fgcolor, 0, config_statusbar_bgcolor)); /* inicjalizujemy wszystkie opisowe bzdurki */ /* XXX możnaby zrobić stałą tablicę, bez realokowania. byłoby * nieco szybciej, bo dość często się wywołuje tą funkcję. */ memset(&formats, 0, sizeof(formats)); #define __add_format(x, y, z) \ { \ formats = xrealloc(formats, (formats_count + 2) * sizeof(struct format_data)); \ formats[formats_count].name = x; \ formats[formats_count].text = (y) ? xstrdup(z) : NULL; \ formats_count++; \ formats[formats_count].name = NULL; \ formats[formats_count].text = NULL; \ } { time_t t = time(NULL); struct tm *tm; char tmp[80]; tm = localtime(&t); strftime(tmp, sizeof(tmp), format_find("ncurses_timestamp"), tm); __add_format("time", 1, tmp); } __add_format("window", window_current->id, itoa(window_current->id)); __add_format("uin", config_uin, itoa(config_uin)); __add_format("nick", (u && u->display), u->display); __add_format("query", window_current->target, window_current->target); __add_format("descr", 1, config_reason); __add_format("mail", (config_check_mail && mail_count), itoa(mail_count)); { string_t s = string_init(""); int first = 1, act = 0; list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->act || !w->id) continue; if (!first) string_append_c(s, ','); string_append(s, (w->act == 2) ? "%W" : "%K"); string_append(s, itoa(w->id)); first = 0; act = 1; } __add_format("activity", (act), s->str); string_free(s, 1); } __add_format("debug", (!window_current->id), ""); __add_format("ffc", (sess && sess->state == GG_STATE_CONNECTED && GG_S_FF(config_status)), ""); __add_format("dnd", (sess && sess->state == GG_STATE_CONNECTED && GG_S_DD(config_status)), ""); __add_format("away", (sess && sess->state == GG_STATE_CONNECTED && GG_S_B(config_status)), ""); __add_format("busy", (sess && sess->state == GG_STATE_CONNECTED && GG_S_B(config_status)), ""); __add_format("avail", (sess && sess->state == GG_STATE_CONNECTED && GG_S_A(config_status)), ""); __add_format("invisible", (sess && sess->state == GG_STATE_CONNECTED && GG_S_I(config_status)), ""); __add_format("notavail", (!sess || sess->state != GG_STATE_CONNECTED), ""); __add_format("more", (window_current->more), ""); __add_format("query_descr", (q && GG_S_D(q->status)), q->descr); __add_format("query_ffc", (q && GG_S_FF(q->status)), ""); __add_format("query_dnd", (q && GG_S_DD(q->status)), ""); __add_format("query_away", (q && GG_S_B(q->status)), ""); __add_format("query_busy", (q && GG_S_B(q->status)), ""); __add_format("query_avail", (q && GG_S_A(q->status)), ""); __add_format("query_invisible", (q && GG_S_I(q->status)), ""); __add_format("query_notavail", (q && GG_S_NA(q->status)), ""); __add_format("query_ip", (q && q->ip.s_addr), inet_ntoa(q->ip)); __add_format("url", 1, "http://ekg.chmurka.net/"); __add_format("version", 1, VERSION); #undef __add_format for (y = 0; y < config_header_size; y++) { const char *p; if (!y) { p = format_find("header1"); if (!strcmp(p, "")) p = format_find("header"); } else { char *tmp = saprintf("header%d", y + 1); p = format_find(tmp); xfree(tmp); } window_printat(header, 0, y, p, formats, config_statusbar_fgcolor, 0, config_statusbar_bgcolor, 1); } for (y = 0; y < config_statusbar_size; y++) { const char *p; if (!y) { p = format_find("statusbar1"); if (!strcmp(p, "")) p = format_find("statusbar"); } else { char *tmp = saprintf("statusbar%d", y + 1); p = format_find(tmp); xfree(tmp); } switch (ui_ncurses_debug) { case 0: window_printat(status, 0, y, p, formats, config_statusbar_fgcolor, 0, config_statusbar_bgcolor, 1); mouse_statusbar_update(0, y, p, formats, 0); break; case 1: { char *tmp = saprintf(" debug: lines_count=%d start=%d height=%d overflow=%d screen_width=%d", window_current->lines_count, window_current->start, window_current->height, window_current->overflow, ui_screen_width); window_printat(status, 0, y, tmp, formats, config_statusbar_fgcolor, 0, config_statusbar_bgcolor, 1); xfree(tmp); mouse_statusbar_update(0, 0, NULL, NULL, 0); break; } case 2: { char *tmp = saprintf(" debug: lines(count=%d,start=%d,index=%d), line(start=%d,index=%d)", array_count(lines), lines_start, lines_index, line_start, line_index); window_printat(status, 0, y, tmp, formats, config_statusbar_fgcolor, 0, config_statusbar_bgcolor, 1); xfree(tmp); mouse_statusbar_update(0, 0, NULL, NULL, 0); break; } } } for (i = 0; formats[i].name; i++) xfree(formats[i].text); xfree(formats); #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(redraw_header, "") ; PYTHON_HANDLE_FOOTER() PYTHON_HANDLE_HEADER(redraw_statusbar, "") ; PYTHON_HANDLE_FOOTER() #endif if (commit) window_commit(); } #ifdef SIGWINCH static void sigwinch_handler(int sig) { ui_need_refresh = 1; } #endif void save_windows() { string_t s = string_init(NULL); int maxid = 0, i; list_t l; xfree(config_windows_layout); for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->floating && w->id > maxid) maxid = w->id; } for (i = 1; i <= maxid; i++) { const char *target = "-"; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id == i) { target = w->target; break; } } if (target) string_append(s, target); if (i < maxid) string_append_c(s, '|'); } for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->floating && (!w->target || strncmp(w->target, "__", 2))) { char *tmp = saprintf("|*%d,%d,%d,%d,%d,%s", w->left, w->top, w->width, w->height, w->frames, w->target); string_append(s, tmp); xfree(tmp); } } config_windows_layout = string_free(s, 0); } /* * ui_ncurses_beep() * * ostentacyjnie wzywa użytkownika do reakcji. */ static void ui_ncurses_beep() { switch (config_beep_title) { case 0: beep(); break; case 1: beep(); case 2: ui_ncurses_beeping = 1; ui_event("xterm_update"); break; } } #ifdef WITH_ASPELL /* * inicjuje slownik, ustawia kodowanie na takie jakie mamy w konfigu. */ void spellcheck_init(void) { AspellCanHaveError *possible_err; if (!config_aspell || in_autoexec) return; print("aspell_init"); if (spell_checker) { delete_aspell_speller(spell_checker); delete_aspell_config(spell_config); spell_checker = NULL; spell_config = NULL; } spell_config = new_aspell_config(); aspell_config_replace(spell_config, "encoding", config_aspell_encoding); aspell_config_replace(spell_config, "lang", config_aspell_lang); possible_err = new_aspell_speller(spell_config); if (aspell_error_number(possible_err) != 0) { spell_checker = NULL; delete_aspell_config(spell_config); spell_config = NULL; print("aspell_init_error", aspell_error_message(possible_err)); config_aspell = 0; } else { spell_checker = to_aspell_speller(possible_err); print("aspell_init_success"); } } void spellcheck_deinit() { if (spell_checker) { delete_aspell_speller(spell_checker); spell_checker = NULL; } if (spell_config) { delete_aspell_config(spell_config); spell_config = NULL; } } #endif /* * mouse_event() * * wywolywane przy zdarzeniach myszy oraz zmianie wartosci zmiennej mouse. * * - event * - "bevent" - zdarzenie przycisku * - "enable" - wlacza obsluge myszy * - "disable" - wylacza obsluge myszy * - "destroy" - jak disable, ale zwalnia mouse_areas */ static void mouse_event (const char *event) { if (!strcmp(event, "bevent")) { MEVENT e; list_t l; struct mouse_area_t *area; if (!config_mouse) { gg_debug(GG_DEBUG_MISC, "// mouse_event(): Safety check engaged!\n"); return; } if (getmouse(&e) != OK) { gg_debug(GG_DEBUG_MISC, "// mouse_event(): getmouse() failed\n"); return; } #if 0 gg_debug(GG_DEBUG_MISC, "// mouse_event(): %d,%d: %d\n", e.x, e.y, e.bstate); #endif /* Najpierw określamy obszar w którym nastąpiło zdarzenie */ for (l = mouse_areas; l; l = l->next) { area = l->data; if (e.x >= area->start.x && e.x <= area->end.x && e.y >= area->start.y && e.y <= area->end.y) break; } if (!l) { gg_debug(GG_DEBUG_MISC, "// mouse_event(): Outside any area.\n"); return; } /* Mamy obszar. Szukamy handlera zdarzenia. */ for (l = area->bevents; l; l = l->next) { struct mouse_bevent_t *be = l->data; if (be->bstate == e.bstate) { struct mouse_coords_t c; c.x = e.x - area->start.x; c.y = e.y - area->start.y; be->handler (&c, e.bstate); break; } } if (!l) gg_debug(GG_DEBUG_MISC, "// mouse_event(): Unhandled button event.\n"); return; } if (!strcmp(event, "enable")) { mousemask(ALL_MOUSE_EVENTS, NULL); return; } if (!strcmp(event, "disable")) { mousemask(0, NULL); return; } if (!strcmp(event, "destroy")) { list_t l; mousemask(0, NULL); for (l = mouse_areas; l; l = l->next) { struct mouse_area_t *a = l->data; xfree(a->name); list_destroy(a->bevents, 1); } list_destroy(mouse_areas, 1); } } /* * mouse_bevent_add() * * dodaje button event (zdarzenie dla przycisku) do obszaru. jesli to * pierwszy bevent, to trzeba zapewnic area->bevent == NULL. * * - area: wskaznik do odpowiedniej struktury area_t * - bstate: jak MEVENT->bstate w mouse(3ncurses) * - hnd: odpowiedni handler typu mouse_handler_t * * 0: udalo sie, -1: nie udalo sie */ static int mouse_bevent_add (struct mouse_area_t *area, mmask_t bstate, mouse_handler_t hnd) { struct mouse_bevent_t e; if (!area) { gg_debug(GG_DEBUG_MISC, "// mouse_bevent_add(): Safety check engaged!\n"); return -1; } e.bstate = bstate; e.handler = hnd; return list_add(&area->bevents, &e, sizeof(struct mouse_bevent_t)) ? 0 : -1; } /* * mouse_area_add() * * dodaje obszar do mouse_areas. * * - area: struktura mouse_area_t * * zwraca wskaznik do nowozaalokowanego obszaru lub NULL - nie udalo sie. */ static struct mouse_area_t *mouse_area_add (struct mouse_area_t *area) { list_t l; /* Sprawdzamy czy nowy obszar nie zachodzi na żaden * istniejący obszar. */ for (l = mouse_areas; l; l = l->next) { struct mouse_area_t *cur_area = l->data; if ((area->start.x >= cur_area->start.x && area->start.x <= cur_area->end.x && area->start.y >= cur_area->start.y && area->start.y >= cur_area->end.y) || (area->start.x + area->size.x >= cur_area->start.x && area->start.x + area->size.x <= cur_area->end.x && area->start.y + area->size.y >= cur_area->start.y && area->start.y + area->size.y >= cur_area->end.y)) { gg_debug(GG_DEBUG_MISC, "// mouse_area_add(): %s (%d,%d)-(%d,%d) overlaps with %s (%d,%d)-(%d,%d)\n", area->name, area->start.x, area->start.y, area->end.x, area->end.y, cur_area->name, cur_area->start.x, cur_area->start.y, cur_area->end.x, cur_area->end.y); return NULL; } } if (!(area = list_add(&mouse_areas, area, sizeof(struct mouse_area_t)))) { gg_debug(GG_DEBUG_MISC, "// mouse_area_add(): list_add() returned NULL\n"); return NULL; } area->name = xstrdup(area->name); area->end.x = area->start.x + area->size.x; area->end.y = area->start.y + area->size.y; return area; } /* * mouse_area_find() * * znajduje obszar po nazwie. * * - name: nazwa do znalezienia * * zwraca wskaznik lub NULL jesli nie znaleziono. */ static struct mouse_area_t *mouse_area_find (const char *name) { list_t l; for (l = mouse_areas; l; l = l->next) { struct mouse_area_t *a = l->data; if (!strcmp(name, a->name)) return a; } return NULL; } /* * mouse_area_del() * * usuwa obszar. * * - name: nazwa obszaru * * 0 - udalo sie, -1 - nie udalo sie */ static int mouse_area_del (const char *name) { struct mouse_area_t *a; if (!(a = mouse_area_find(name))) return -1; xfree(a->name); list_destroy(a->bevents, 1); /* Na wypadek, gdyby list_remove sie nie udalo - lepiej nie syfic. */ memset (a, 0, sizeof(struct mouse_area_t)); return list_remove(&mouse_areas, a, 1); } /* * mouse_area_resize() * * zmienia rozmiar obszaru. * * - name: nazwa obszaru * - y, x: nowy rozmiar * * NULL - nie udalo sie, w przeciwnym razie wskaznik na obszar. */ static struct mouse_area_t *mouse_area_resize (const char *name, int y, int x) { struct mouse_area_t *a; if (!(a = mouse_area_find(name))) return NULL; a->size.x = x; a->size.y = y; a->end.x = a->start.x + a->size.x; a->end.y = a->start.y + a->size.y; return a; } /* * mouse_area_move() * * przesuwa obszar. * * - name: nazwa obszaru * - y, x: nowe polozenie * * NULL - nie udalo sie, w przeciwnym razie wskaznik na obszar. */ static struct mouse_area_t *mouse_area_move (const char *name, int y, int x) { struct mouse_area_t *a; if (!(a = mouse_area_find(name))) return NULL; a->start.x = x; a->start.y = y; a->end.x = a->start.x + a->size.x; a->end.y = a->start.y + a->size.y; return a; } /* * mouse_in_area() * * sprawdza, czy punkt należy do obszaru. * * - start - początek obszaru. * - end - koniec obszaru. * - point - punkt. * * 0 - nie należy, 1 - należy. */ static int mouse_in_area (struct mouse_coords_t *start, struct mouse_coords_t *end, struct mouse_coords_t *point) { #if 0 gg_debug(GG_DEBUG_MISC, "// mouse_in_area(): {(%d,%d), (%d,%d)}, (%d,%d)\n", start->x, start->y, end->x, end->y, point->x, point->y); #endif if (start->x == -1 || start->y == -1 || end->x == -1 || end->y == -1) return 0; return (point->x >= start->x && point->x <= end->x && point->y >= start->y && point->y <= end->y) ? 1 : 0; } /* * mouse_bevent_header() * * bevent na headerze. * * - coords - koordynaty * - bstate - stan przyciskow */ static void mouse_bevent_header (struct mouse_coords_t *coords, mmask_t bstate) { char *tmp; if (bstate == BUTTON1_DOUBLE_CLICKED) tmp = saprintf("/find -u %s", window_current->target); else tmp = saprintf("/list %s", window_current->target); command_exec(window_current->target, tmp, 0); xfree(tmp); } /* * mouse_bevent_statusbar() * * bevent na pasku stanu. * * - coords - koordynaty * - bstate - stan przyciskow */ static void mouse_bevent_statusbar (struct mouse_coords_t *coords, mmask_t bstate) { enum area_t { TIME = 0, UIN, MORE, QUERY, WINDOW, ACT } area; int act_pos = 0; char *cmd = NULL; /* komenda do wykonania */ if (mouse_in_area(&mouse_statusbar.time_c[0], &mouse_statusbar.time_c[1], coords)) area = TIME; else if (mouse_in_area(&mouse_statusbar.uin_c[0], &mouse_statusbar.uin_c[1], coords)) area = UIN; else if (mouse_in_area(&mouse_statusbar.more_c[0], &mouse_statusbar.more_c[1], coords)) area = MORE; else if (mouse_in_area(&mouse_statusbar.query_c[0], &mouse_statusbar.query_c[1], coords)) area = QUERY; else if (mouse_in_area(&mouse_statusbar.window_c[0], &mouse_statusbar.window_c[1], coords)) area = WINDOW; else if (mouse_in_area(&mouse_statusbar.act_c[0], &mouse_statusbar.act_c[1], coords)) { area = ACT; act_pos = coords->x - mouse_statusbar.act_c[0].x; if (act_pos >= strlen(mouse_statusbar.act_str)) { gg_debug(GG_DEBUG_MISC, "// mouse_statusbar_bevent(): Sanity check engaged: %d >= %d\n", act_pos, strlen(mouse_statusbar.act_str)); return; } } else { gg_debug(GG_DEBUG_MISC, "// mouse_statusbar_bevent(): Outside any area\n"); return; } #if 0 gg_debug(GG_DEBUG_MISC, "// mouse_statusbar_bevent(): area=%d\n", area); #endif /* teraz area zawiera enum odpowiadający obszarowi, na którym pojawiło * się zdarzenie a window zawiera numer okna dla area == ACT */ if (area == TIME && bstate == BUTTON1_CLICKED) cmd = xstrdup("/exec ^date"); else if (area == UIN) { if (bstate == BUTTON1_CLICKED) cmd = xstrdup("/status"); else if (bstate == BUTTON1_DOUBLE_CLICKED) cmd = saprintf("/find %d", config_uin); } else if (area == MORE) { binding_forward_page(NULL); return; } else if (area == QUERY) { if (bstate == BUTTON1_CLICKED) cmd = xstrdup("/list $"); else if (bstate == BUTTON3_CLICKED) cmd = xstrdup("/find $"); } else if (area == WINDOW && bstate == BUTTON1_CLICKED) cmd = xstrdup("/window list $"); else if (area == ACT) { char *num_str; int num_start = -1, num_end = -1; int num; int act_str_len = strlen(mouse_statusbar.act_str); /* act_pos określa pozycję w act_str. musimy znaleźć początek * i koniec numerka w stringu. początek to przecinek+1 lub * początek stringa, koniec to przecinek lub koniec stringa. */ if (mouse_statusbar.act_str[act_pos] == ',') return; /* najpierw początek */ for (num_start = act_pos; num_start; num_start--) if (mouse_statusbar.act_str[num_start] == ',') { num_start++; break; } /* teraz koniec */ for (num_end = act_pos; num_end < act_str_len; num_end++) if (mouse_statusbar.act_str[num_end] == ',') break; num_str = xmalloc(num_end - num_start + 1); memcpy(num_str, mouse_statusbar.act_str + num_start, num_end - num_start); num_str[num_end - num_start] = 0; #if 0 gg_debug(GG_DEBUG_MISC, "// mouse_statusbar_bevent(): act str: '%s' (%d-%d)\n", num_str, num_start, num_end); #endif num = atoi(num_str); xfree(num_str); if (bstate == BUTTON1_CLICKED) cmd = saprintf("/window list %d", num); else if (bstate == BUTTON1_DOUBLE_CLICKED) cmd = saprintf("/window switch %d", num); } if (!cmd) return; command_exec(window_current->target, cmd, 0); xfree(cmd); } /* * mouse_bevent_current() * * bevent dla window_current. * * - coords - koordynaty * - bstate - stan przyciskow */ static void mouse_bevent_current (struct mouse_coords_t *coords, mmask_t bstate) { static struct mouse_coords_t saved_coords = {-1, -1}; struct mouse_coords_t distance; char *cmd = NULL; enum { DIR_UP = 0, DIR_DOWN, DIR_LEFT, DIR_RIGHT } dir; if (bstate == BUTTON1_PRESSED || bstate == BUTTON3_PRESSED) { /* wciśnięto któryś przycisk - zapamiętujemy pozycję */ memcpy(&saved_coords, coords, sizeof(saved_coords)); return; } /* puszczono któryś przycisk. sprawdzamy kierunek gestu. */ if (saved_coords.x == -1 || saved_coords.y == -1) { /* przycisk puszczony dwa razy? może były trzymane dwa */ gg_debug(GG_DEBUG_MISC, "// mouse_bevent_current(): Safety check engaged!\n"); return; } distance.x = coords->x - saved_coords.x; distance.y = coords->y - saved_coords.y; /* mamy przyrosty, obliczamy odległości */ #define __negative(x) ((x) < 0) #define __value(x) (__negative(x) ? -(x) : (x)) if (__value(distance.x) > 2 * __value(distance.y)) { /* poziomo */ dir = __negative(distance.x) ? DIR_LEFT : DIR_RIGHT; } else if (__value(distance.y) > 2 * __value(distance.x)) { /* pionowo */ dir = __negative(distance.y) ? DIR_UP : DIR_DOWN; } else { gg_debug(GG_DEBUG_MISC, "// mouse_bevent_current(): Unknown gesture (distance=(%d,%d))!\n", distance.x, distance.y); goto out; } #undef __value #undef __negative #if 0 gg_debug(GG_DEBUG_MISC, "// mouse_bevent_current(): Gesture dir %d\n", dir); #endif if (dir == DIR_LEFT) cmd = saprintf("/window prev"); else if (dir == DIR_RIGHT) cmd = saprintf("/window next"); else if (dir == DIR_UP) cmd = saprintf("/window last"); else if (dir == DIR_DOWN && bstate == BUTTON1_RELEASED) cmd = saprintf("/window oldest"); else if (dir == DIR_DOWN && bstate == BUTTON1_RELEASED) cmd = saprintf("/window active"); if (!cmd) goto out; gg_debug(GG_DEBUG_MISC, "// mouse bevent_current(): Doing command: %s\n", cmd); command_exec(window_current->target, cmd, 0); xfree(cmd); out: saved_coords.x = saved_coords.y = -1; } /* * ui_ncurses_init() * * inicjalizuje całą zabawę z ncurses. */ void ui_ncurses_init() { int background = COLOR_BLACK; struct mouse_area_t area; ui_postinit = ui_ncurses_postinit; ui_print = ui_ncurses_print; ui_loop = ui_ncurses_loop; ui_beep = ui_ncurses_beep; ui_event = ui_ncurses_event; ui_deinit = ui_ncurses_deinit; initscr(); cbreak(); noecho(); nonl(); if (config_display_transparent) { background = COLOR_DEFAULT; use_default_colors(); } ui_screen_width = stdscr->_maxx + 1; ui_screen_height = stdscr->_maxy + 1; ui_need_refresh = 0; #ifndef GG_DEBUG_DISABLE window_new(NULL, -1); #endif window_current = window_new(NULL, 0); status = newwin(1, stdscr->_maxx + 1, stdscr->_maxy - 1, 0); input = newwin(1, stdscr->_maxx + 1, stdscr->_maxy, 0); keypad(input, TRUE); nodelay(input, TRUE); mouse_event("disable"); area.name = "status"; area.size.y = 1; area.size.x = stdscr->_maxx + 1; area.start.y = stdscr->_maxy - 1; area.start.x = 0; area.bevents = NULL; mouse_bevent_add(&area, BUTTON1_CLICKED, mouse_bevent_statusbar); mouse_bevent_add(&area, BUTTON1_DOUBLE_CLICKED, mouse_bevent_statusbar); mouse_bevent_add(&area, BUTTON3_CLICKED, mouse_bevent_statusbar); mouse_area_add(&area); area.name = "window_current"; area.size.y = window_current->window->_maxy; area.size.x = window_current->window->_maxx; area.start.y = window_current->window->_begy; area.start.x = window_current->window->_begx; area.bevents = NULL; mouse_bevent_add(&area, BUTTON1_PRESSED, mouse_bevent_current); mouse_bevent_add(&area, BUTTON1_RELEASED, mouse_bevent_current); mouse_bevent_add(&area, BUTTON3_PRESSED, mouse_bevent_current); mouse_bevent_add(&area, BUTTON3_RELEASED, mouse_bevent_current); mouse_area_add(&area); start_color(); init_pair(7, COLOR_BLACK, background); /* małe obejście domyślnego koloru */ init_pair(1, COLOR_RED, background); init_pair(2, COLOR_GREEN, background); init_pair(3, COLOR_YELLOW, background); init_pair(4, COLOR_BLUE, background); init_pair(5, COLOR_MAGENTA, background); init_pair(6, COLOR_CYAN, background); #define __init_bg(x, y) \ init_pair(x, COLOR_BLACK, y); \ init_pair(x + 1, COLOR_RED, y); \ init_pair(x + 2, COLOR_GREEN, y); \ init_pair(x + 3, COLOR_YELLOW, y); \ init_pair(x + 4, COLOR_BLUE, y); \ init_pair(x + 5, COLOR_MAGENTA, y); \ init_pair(x + 6, COLOR_CYAN, y); \ init_pair(x + 7, COLOR_WHITE, y); __init_bg(8, COLOR_RED); __init_bg(16, COLOR_GREEN); __init_bg(24, COLOR_YELLOW); __init_bg(32, COLOR_BLUE); __init_bg(40, COLOR_MAGENTA); __init_bg(48, COLOR_CYAN); __init_bg(56, COLOR_WHITE); #undef __init_bg contacts_changed(); window_commit(); /* deaktywujemy klawisze INTR, QUIT, SUSP i DSUSP */ if (!tcgetattr(0, &old_tio)) { struct termios tio; memcpy(&tio, &old_tio, sizeof(tio)); tio.c_cc[VINTR] = _POSIX_VDISABLE; tio.c_cc[VQUIT] = _POSIX_VDISABLE; #ifdef VDSUSP tio.c_cc[VDSUSP] = _POSIX_VDISABLE; #endif #ifdef VSUSP tio.c_cc[VSUSP] = _POSIX_VDISABLE; #endif tcsetattr(0, TCSADRAIN, &tio); } #ifdef SIGWINCH { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigwinch_handler; sigaction(SIGWINCH, &sa, NULL); } #endif memset(history, 0, sizeof(history)); timer_add(1, 1, TIMER_UI, 0, "ui-ncurses-time", "refresh_time"); memset(binding_map, 0, sizeof(binding_map)); memset(binding_map_meta, 0, sizeof(binding_map_meta)); binding_default(); ui_ncurses_inited = 1; } /* * ui_ncurses_postinit() * * uruchamiana po wczytaniu konfiguracji. */ static void ui_ncurses_postinit() { if (config_windows_save && config_windows_layout) { char **targets = array_make(config_windows_layout, "|", 0, 0, 0); int i; if (targets[0] && strcmp(targets[0], "")) { xfree(window_current->target); xfree(window_current->prompt); window_current->target = xstrdup(targets[0]); window_current->prompt = format_string(format_find("ncurses_prompt_query"), targets[0]); window_current->prompt_len = strlen(window_current->prompt); } for (i = 1; targets[i]; i++) { if (!strcmp(targets[i], "-")) continue; window_new((strcmp(targets[i], "")) ? targets[i] : NULL, i + 1); } array_free(targets); } #ifdef WITH_ASPELL spellcheck_init(); #endif } /* * ui_ncurses_deinit() * * zamyka, robi porządki. */ static void ui_ncurses_deinit() { static int done = 0; list_t l; int i; if (!ui_ncurses_inited) return; if (done) return; done = 1; if (config_windows_save & 1) save_windows(); for (l = windows; l; ) { struct window *w = l->data; l = l->next; window_kill(w, 1); } list_destroy(windows, 1); tcsetattr(0, TCSADRAIN, &old_tio); mouse_event("destroy"); keypad(input, FALSE); werase(input); wnoutrefresh(input); doupdate(); delwin(input); delwin(status); if (contacts) delwin(contacts); if (header) delwin(header); endwin(); if (mouse_statusbar_pending.act_str) { xfree(mouse_statusbar_pending.act_str); mouse_statusbar_pending.act_str = NULL; } if (mouse_statusbar.act_str) { xfree(mouse_statusbar.act_str); mouse_statusbar.act_str = NULL; } for (i = 0; i < HISTORY_MAX; i++) if (history[i] != line) { xfree(history[i]); history[i] = NULL; } if (lines) { for (i = 0; lines[i]; i++) { if (lines[i] != line) xfree(lines[i]); lines[i] = NULL; } xfree(lines); lines = NULL; } xfree(line); #ifdef WITH_ASPELL if (spell_checker) delete_aspell_speller(spell_checker); if (spell_config) delete_aspell_config(spell_config); xfree(aspell_line); #endif xfree(yanked); if (getenv("TERM") && !strncmp(getenv("TERM"), "xterm", 5) && !getenv("EKG_NO_TITLE")) write(1, "\033]2;\007", 5); } /* * line_adjust() * * ustawia kursor w odpowiednim miejscu ekranu po zmianie tekstu w poziomie. */ static void line_adjust() { int prompt_len = (lines) ? 0 : window_current->prompt_len; line_index = strlen(line); if (strlen(line) < input->_maxx - 9 - prompt_len) line_start = 0; else line_start = strlen(line) - strlen(line) % (input->_maxx - 9 - prompt_len); } /* * lines_adjust() * * poprawia kursor po przesuwaniu go w pionie. */ static void lines_adjust() { if (lines_index < lines_start) lines_start = lines_index; if (lines_index - 4 > lines_start) lines_start = lines_index - 4; line = lines[lines_index]; if (line_index > strlen(line)) line_index = strlen(line); } void dcc_generator(const char *text, int len) { const char *words[] = { "close", "get", "send", "list", "resume", "rsend", "rvoice", "voice", NULL }; int i; for (i = 0; words[i]; i++) if (!strncasecmp(text, words[i], len)) array_add(&completions, xstrdup(words[i])); } void command_generator(const char *text, int len) { const char *slash = "", *dash = ""; list_t l; if (*text == '/') { slash = "/"; text++; len--; } if (*text == '^') { dash = "^"; text++; len--; } if (window_current->target) slash = "/"; for (l = commands; l; l = l->next) { struct command *c = l->data; if (!strncasecmp(text, c->name, len)) array_add(&completions, saprintf("%s%s%s", slash, dash, c->name)); } } void events_generator(const char *text, int len) { int i; const char *tmp = NULL; char *pre = NULL; if ((tmp = strrchr(text, '|')) || (tmp = strrchr(text, ','))) { char *foo; pre = xstrdup(text); foo = strrchr(pre, *tmp); *(foo + 1) = 0; len -= tmp - text + 1; tmp = tmp + 1; } else tmp = text; for (i = 0; event_labels[i].name; i++) if (!strncasecmp(tmp, event_labels[i].name, len)) array_add(&completions, ((tmp == text) ? xstrdup(event_labels[i].name) : saprintf("%s%s", pre, event_labels[i].name))); xfree(pre); } void ignorelevels_generator(const char *text, int len) { int i; const char *tmp = NULL; char *pre = NULL; if ((tmp = strrchr(text, '|')) || (tmp = strrchr(text, ','))) { char *foo; pre = xstrdup(text); foo = strrchr(pre, *tmp); *(foo + 1) = 0; len -= tmp - text + 1; tmp = tmp + 1; } else tmp = text; for (i = 0; ignore_labels[i].name; i++) if (!strncasecmp(tmp, ignore_labels[i].name, len)) array_add(&completions, ((tmp == text) ? xstrdup(ignore_labels[i].name) : saprintf("%s%s", pre, ignore_labels[i].name))); xfree(pre); } void unknown_uin_generator(const char *text, int len) { int i; for (i = 0; i < send_nicks_count; i++) { if (send_nicks[i] && xisdigit(send_nicks[i][0]) && !strncasecmp(text, send_nicks[i], len)) if (!array_contains(completions, send_nicks[i], 0)) array_add(&completions, xstrdup(send_nicks[i])); } } void known_uin_generator(const char *text, int len) { list_t l; int done = 0; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (u->display && u->uin && !strncasecmp(text, u->display, len)) { array_add_check(&completions, xstrdup(u->display), 1); done = 1; } } for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!done && u->uin && !strncasecmp(text, itoa(u->uin), len)) array_add_check(&completions, xstrdup(itoa(u->uin)), 1); } for (l = conferences; l; l = l->next) { struct conference *c = l->data; if (!strncasecmp(text, c->name, len)) array_add_check(&completions, xstrdup(c->name), 1); } unknown_uin_generator(text, len); } void variable_generator(const char *text, int len) { list_t l; for (l = variables; l; l = l->next) { struct variable *v = l->data; if (v->type == VAR_FOREIGN || !v->ptr) continue; if (*text == '-') { if (!strncasecmp(text + 1, v->name, len - 1)) array_add(&completions, saprintf("-%s", v->name)); } else { if (!strncasecmp(text, v->name, len)) array_add(&completions, xstrdup(v->name)); } } } void ignored_uin_generator(const char *text, int len) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!ignored_check(u->uin)) continue; if (!u->display) { if (!strncasecmp(text, itoa(u->uin), len)) array_add(&completions, xstrdup(itoa(u->uin))); } else { if (u->display && !strncasecmp(text, u->display, len)) array_add(&completions, xstrdup(u->display)); } } } void blocked_uin_generator(const char *text, int len) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!group_member(u, "__blocked")) continue; if (!u->display) { if (!strncasecmp(text, itoa(u->uin), len)) array_add(&completions, xstrdup(itoa(u->uin))); } else { if (u->display && !strncasecmp(text, u->display, len)) array_add(&completions, xstrdup(u->display)); } } } void empty_generator(const char *text, int len) { } void file_generator(const char *text, int len) { struct dirent **namelist = NULL; char *dname, *tmp; const char *fname; int count, i; /* `dname' zawiera nazwę katalogu z kończącym znakiem `/', albo * NULL, jeśli w dopełnianym tekście nie ma ścieżki. */ dname = xstrdup(text); if ((tmp = strrchr(dname, '/'))) { tmp++; *tmp = 0; } else { xfree(dname); dname = NULL; } /* `fname' zawiera nazwę szukanego pliku */ fname = strrchr(text, '/'); if (fname) fname++; else fname = text; again: /* zbierzmy listę plików w żądanym katalogu */ count = scandir((dname) ? dname : ".", &namelist, NULL, alphasort); ui_debug("dname=\"%s\", fname=\"%s\", count=%d\n", (dname) ? dname : "(null)", (fname) ? fname : "(null)", count); for (i = 0; i < count; i++) { char *name = namelist[i]->d_name, *tmp = saprintf("%s%s", (dname) ? dname : "", name); struct stat st; int isdir = 0; if (!stat(tmp, &st)) isdir = S_ISDIR(st.st_mode); xfree(tmp); if (!strcmp(name, ".")) { xfree(namelist[i]); continue; } /* jeśli mamy `..', sprawdź czy katalog składa się z * `../../../' lub czegoś takiego. */ if (!strcmp(name, "..")) { const char *p; int omit = 0; for (p = dname; p && *p; p++) { if (*p != '.' && *p != '/') { omit = 1; break; } } if (omit) { xfree(namelist[i]); continue; } } if (!strncmp(name, fname, strlen(fname))) { name = saprintf("%s%s%s", (dname) ? dname : "", name, (isdir) ? "/" : ""); array_add(&completions, name); } xfree(namelist[i]); } /* jeśli w dopełnieniach wylądował tylko jeden wpis i jest katalogiem * to wejdź do niego i szukaj jeszcze raz */ if (array_count(completions) == 1 && strlen(completions[0]) > 0 && completions[0][strlen(completions[0]) - 1] == '/') { xfree(dname); dname = xstrdup(completions[0]); fname = ""; xfree(namelist); namelist = NULL; array_free(completions); completions = NULL; goto again; } xfree(dname); xfree(namelist); } void python_generator(const char *text, int len) { const char *words[] = { "exec", "list", "load", "restart", "run", "unload", NULL }; int i; for (i = 0; words[i]; i++) if (!strncasecmp(text, words[i], len)) array_add(&completions, xstrdup(words[i])); } void window_generator(const char *text, int len) { const char *words[] = { "new", "kill", "move", "next", "resize", "prev", "switch", "clear", "refresh", "list", "active", "last", "dump", "swap", NULL }; int i; for (i = 0; words[i]; i++) if (!strncasecmp(text, words[i], len)) array_add(&completions, xstrdup(words[i])); } void reason_generator(const char *text, int len) { if (config_reason && !strncasecmp(text, config_reason, len)) { char *reason; /* brzydkie rozwiązanie, żeby nie ruszać opisu przy dopełnianiu */ if (xisspace(*config_reason)) reason = saprintf("\001\\%s", config_reason); else reason = saprintf("\001%s", config_reason); array_add(&completions, reason); } } static struct { char ch; void (*generate)(const char *text, int len); } generators[] = { { 'u', known_uin_generator }, { 'U', unknown_uin_generator }, { 'c', command_generator }, { 's', empty_generator }, { 'i', ignored_uin_generator }, { 'b', blocked_uin_generator }, { 'v', variable_generator }, { 'd', dcc_generator }, { 'p', python_generator }, { 'w', window_generator }, { 'f', file_generator }, { 'e', events_generator }, { 'I', ignorelevels_generator }, { 'r', reason_generator }, { 0, NULL } }; /* * complete() * * funkcja obsługująca dopełnianie klawiszem tab. * * Działanie: * - Wprowadzona linia dzielona jest na wyrazy (uwzględniając przecinki i znaki cudzyslowia) * - następnie znaki separacji znajdujące się między tymi wyrazami wrzucane są do tablicy separators * - dalej sprawdzane jest za pomocą zmiennej word_current (określającej aktualny wyraz bez uwzględnienia * przecinków - po to, aby wiedzieć czy w przypadku np funkcji /query ma być szukane dopełnienie * - zmienna word odpowiada za aktualny wyraz (*z* uwzględnieniem przecinków) * - words - tablica zawierają wszystkie wyrazy * - gdy jest to możliwe szukane jest dopełnienie * - gdy dopełnień jest więcej niż jedno (count > 1) wyświetlamy tylko "wspólną" część wszystkich dopełnień * np ,,que'' w przypadku funkcji /query i /queue * - gdy dopełnienie jest tylko jedno wyświetlamy owo dopełnienie * - przy wyświetlaniu dopełnienia cała linijka konstruowana jest od nowa, ponieważ nie wiadomo w którym miejscu * podany wyraz ma zostań "wsadzony", stąd konieczna jest tablica separatorów, tablica wszystkich wyrazów itd ... */ static void complete(int *line_start, int *line_index) { char *start, *cmd, **words, *separators; int i, count, word, j, words_count, word_current, open_quote; start = xmalloc(strlen(line) + 1); /* * jeśli uzbierano już coś to próbujemy wyświetlić wszystkie możliwości */ if (completions) { int maxlen = 0, cols, rows; char *tmp; for (i = 0; completions[i]; i++) if (strlen(completions[i]) + 2 > maxlen) maxlen = strlen(completions[i]) + 2; cols = (window_current->width - 6) / maxlen; if (cols == 0) cols = 1; rows = array_count(completions) / cols + 1; tmp = xmalloc(cols * maxlen + 2); for (i = 0; i < rows; i++) { int j; strcpy(tmp, ""); for (j = 0; j < cols; j++) { int cell = j * rows + i; if (cell < array_count(completions)) { int k; strcat(tmp, completions[cell]); for (k = 0; k < maxlen - strlen(completions[cell]); k++) strcat(tmp, " "); } } if (strcmp(tmp, "")) { print("none", tmp); } } xfree(tmp); xfree(start); return; } /* zerujemy co mamy */ words = NULL; /* podziel (uwzględniając cudzysłowia)*/ for (i = 0, j = 0, open_quote = 0; i < strlen(line); i++) { if(line[i] == '"') { for(j = 0, i++; i < strlen(line) && line[i] != '"'; i++, j++) start[j] = line[i]; if (i == strlen(line)) open_quote = 1; } else for(j = 0; i < strlen(line) && !xisspace(line[i]) && line[i] != ','; j++, i++) start[j] = line[i]; start[j] = '\0'; /* "przewijamy" większą ilość spacji */ for(i++; i < strlen(line) && (xisspace(line[i]) || line[i] == ','); i++); i--; array_add(&words, saprintf("%s", start)); } /* jeżeli ostatnie znaki to spacja, albo przecinek to trzeba dodać jeszcze pusty wyraz do words */ if (strlen(line) > 1 && (line[strlen(line) - 1] == ' ' || line[strlen(line) - 1] == ',') && !open_quote) array_add(&words, xstrdup("")); /* for(i = 0; i < array_count(words); i++) gg_debug(GG_DEBUG_MISC, "words[i = %d] = \"%s\"\n", i, words[i]); */ /* inicjujemy pamięc dla separators */ if (words != NULL) separators = xmalloc(array_count(words) + 1); else separators = NULL; /* sprawdź, gdzie jesteśmy (uwzgędniając cudzysłowia) i dodaj separatory*/ for (word = 0, i = 0; i < strlen(line); i++, word++) { if(line[i] == '"') { for(j = 0, i++; i < strlen(line) && line[i] != '"'; j++, i++) start[j] = line[i]; } else { for(j = 0; i < strlen(line) && !xisspace(line[i]) && line[i] != ','; j++, i++) start[j] = line[i]; } /* "przewijamy */ for(i++; i < strlen(line) && (xisspace(line[i]) || line[i] == ','); i++); /* ustawiamy znak końca */ start[j] = '\0'; /* jeżeli to koniec linii, to kończymy tą zabawę */ if(i >= strlen(line)) break; /* obniżamy licznik o 1, żeby wszystko było okey, po "przewijaniu" */ i--; /* hmm, jesteśmy już na wyrazie wskazywany przez kursor ? */ if(i >= *line_index) break; } /* dodajmy separatory - pewne rzeczy podobne do pętli powyżej */ for (i = 0, j = 0; i < strlen(line); i++, j++) { if(line[i] == '"') { for(i++; i < strlen(line) && line[i] != '"'; i++); if(i < strlen(line)) separators[j] = line[i + 1]; } else { for(; i < strlen(line) && !xisspace(line[i]) && line[i] != ','; i++); separators[j] = line[i]; } for(i++; i < strlen(line) && (xisspace(line[i]) || line[i] == ','); i++); i--; } if (separators) separators[j] = '\0'; // koniec ciagu /* aktualny wyraz bez uwzgledniania przecinkow */ for (i = 0, words_count = 0, word_current = 0; i < strlen(line); i++, words_count++) { for(; i < strlen(line) && !xisspace(line[i]); i++) if(line[i] == '"') for(i++; i < strlen(line) && line[i] != '"'; i++); for(i++; i < strlen(line) && xisspace(line[i]); i++); if(i >= strlen(line)) word_current = words_count + 1; i--; /* hmm, jesteśmy już na wyrazie wskazywany przez kursor ? */ if(i >= *line_index) break; } /* trzeba pododawać trochę do liczników w spefycicznych (patrz warunki) sytuacjach */ if (strlen(line) > 1) { if((xisspace(line[strlen(line) - 1]) || line[strlen(line) - 1] == ',') && word + 1== array_count(words) -1 ) word++; if(xisspace(line[strlen(line) - 1]) && words_count == word_current) word_current++; if(xisspace(line[strlen(line) - 1])) words_count++; } /* gg_debug(GG_DEBUG_MISC, "word = %d\n", word); gg_debug(GG_DEBUG_MISC, "start = \"%s\"\n", start); gg_debug(GG_DEBUG_MISC, "words_count = %d\n", words_count); gg_debug(GG_DEBUG_MISC, "word_current = %d\n", word_current); */ /* for(i = 0; i < strlen(separators); i++) gg_debug(GG_DEBUG_MISC, "separators[i = %d] = \"%c\"\n", i, separators[i]); */ cmd = saprintf("/%s ", (config_tab_command) ? config_tab_command : "chat"); /* nietypowe dopełnienie nicków przy rozmowach */ if (!strcmp(line, "") || (!strncasecmp(line, cmd, strlen(cmd)) && word == 2 && send_nicks_count > 0) || (!strcasecmp(line, cmd) && send_nicks_count > 0)) { if (send_nicks_index >= send_nicks_count) send_nicks_index = 0; if (send_nicks_count) { char *nick = send_nicks[send_nicks_index++]; snprintf(line, LINE_MAXLEN, (strchr(nick, ' ')) ? "%s\"%s\" " : "%s%s ", cmd, nick); } else snprintf(line, LINE_MAXLEN, "%s", cmd); *line_start = 0; *line_index = strlen(line); array_free(completions); array_free(words); xfree(start); xfree(separators); xfree(cmd); return; } xfree(cmd); /* początek komendy? */ if (word == 0) command_generator(start, strlen(start)); else { char *params = NULL; int abbrs = 0, i; list_t l; for (l = commands; l; l = l->next) { struct command *c = l->data; int len = strlen(c->name); char *cmd = (line[0] == '/') ? line + 1 : line; if (!strncasecmp(cmd, c->name, len) && xisspace(cmd[len])) { params = c->params; abbrs = 1; break; } for (len = 0; cmd[len] && cmd[len] != ' '; len++); if (!strncasecmp(cmd, c->name, len)) { params = c->params; abbrs++; } else if (params && abbrs == 1) break; } if (params && abbrs == 1) { for (i = 0; generators[i].ch; i++) { if (generators[i].ch == params[word_current - 2]) { int j; generators[i].generate(words[word], strlen(words[word])); for (j = 0; completions && completions[j]; j++) { string_t s; if (!strchr(completions[j], '"') && !strchr(completions[j], '\\') && !strchr(completions[j], ' ')) continue; s = string_init("\""); string_append(s, completions[j]); string_append_c(s, '\"'); xfree(completions[j]); completions[j] = string_free(s, 0); } break; } } } } count = array_count(completions); /* * jeśli jest tylko jedna możlwiość na dopełnienie to drukujemy co mamy, * ewentualnie bierzemy część wyrazów w cudzysłowia ... * i uważamy oczywiście na \001 (patrz funkcje wyżej */ if (count == 1) { line[0] = '\0'; for(i = 0; i < array_count(words); i++) { if(i == word) { if(strchr(completions[0], '\001')) { if(completions[0][0] == '"') strncat(line, completions[0] + 2, strlen(completions[0]) - 2 - 1 ); else strncat(line, completions[0] + 1, strlen(completions[0]) - 1); } else strcat(line, completions[0]); *line_index = strlen(line) + 1; } else { if(strchr(words[i], ' ')) { char *buf = saprintf("\"%s\"", words[i]); strcat(line, buf); xfree(buf); } else strcat(line, words[i]); } if((i == array_count(words) - 1 && line[strlen(line) - 1] != ' ' )) strcat(line, " "); else if (line[strlen(line) - 1] != ' ') { size_t slen = strlen(line); line[slen] = separators[i]; line[slen + 1] = '\0'; } } array_free(completions); completions = NULL; } /* * gdy jest więcej możliwości to robimy podobnie jak wyżej tyle, że czasem * trzeba użyć cudzysłowia tylko z jednej storny, no i trzeba dopełnić do pewnego miejsca * w sumie proste rzeczy, ale jak widać jest trochę opcji ... */ if (count > 1) { int common = 0; int tmp = 0; int quotes = 0; char *s1 = completions[0]; if (*s1 =='"') s1++; /* * może nie za ładne programowanie, ale skuteczne i w sumie jedyne w 100% spełniające * wymagania dopełniania (uwzględnianie cudzywsłowiów itp...) */ for(i=1, j = 0; ; i++, common++) { for(j=0; j < count; j++) { char *s2; s2 = completions[j]; if (*s2 == '"') { s2++; quotes = 1; } tmp = strncasecmp(s1, s2, i); /* gg_debug(GG_DEBUG_MISC,"strncasecmp(\"%s\", \"%s\", %d) = %d\n", s1, s2, i, strncasecmp(s1, s2, i)); */ if (tmp) break; } if (tmp) break; } /* gg_debug(GG_DEBUG_MISC,"common :%d\n", common); */ if (strlen(line) + common < LINE_MAXLEN) { line[0] = '\0'; for(i = 0; i < array_count(words); i++) { if(i == word) { if(quotes == 1 && completions[0][0] != '"') strcat(line, "\""); if(completions[0][0] == '"') common++; if(common > 0 && completions[0][common - 1] == '"') common--; strncat(line, completions[0], common); *line_index = strlen(line); } else { if(strrchr(words[i], ' ')) { char *buf; buf = saprintf("\"%s\"", words[i]); strcat(line, buf); xfree(buf); } else strcat(line, words[i]); } if (separators[i]) { size_t slen = strlen(line); line[slen] = separators[i]; line[slen + 1] = '\0'; } } } } array_free(words); xfree(start); xfree(separators); return; } /* * update_input() * * uaktualnia zmianę rozmiaru pola wpisywania tekstu -- przesuwa okienka * itd. jeśli zmieniono na pojedyncze, czyści dane wejściowe. */ static void update_input() { if (input_size == 1) { int i; for (i = 0; lines[i]; i++) xfree(lines[i]); xfree(lines); lines = NULL; line = xmalloc(LINE_MAXLEN); strlcpy(line, "", LINE_MAXLEN); history[0] = line; line_start = 0; line_index = 0; lines_start = 0; lines_index = 0; } else { lines = xmalloc(2 * sizeof(char*)); lines[0] = xmalloc(LINE_MAXLEN); lines[1] = NULL; strlcpy(lines[0], line, LINE_MAXLEN); xfree(line); line = lines[0]; history[0] = NULL; lines_start = 0; lines_index = 0; } window_resize(); window_redraw(window_current); touchwin(window_current->window); window_commit(); } /* * print_char() * * wyświetla w danym okienku znak, biorąc pod uwagę znaki ,,niewyświetlalne''. */ void print_char(WINDOW *w, int y, int x, unsigned char ch) { wattrset(w, A_NORMAL); if (ch < 32) { wattrset(w, A_REVERSE); ch += 64; } if (ch >= 128 && ch < 160) { ch = '?'; wattrset(w, A_REVERSE); } mvwaddch(w, y, x, ch); wattrset(w, A_NORMAL); } /* * print_char_underlined() * * wyświetla w danym okienku podkreslony znak, biorąc pod uwagę znaki ,,niewyświetlalne''. */ void print_char_underlined(WINDOW *w, int y, int x, unsigned char ch) { wattrset(w, A_UNDERLINE); if (ch < 32) { wattrset(w, A_REVERSE | A_UNDERLINE); ch += 64; } if (ch >= 128 && ch < 160) { ch = '?'; wattrset(w, A_REVERSE | A_UNDERLINE); } mvwaddch(w, y, x, ch); wattrset(w, A_NORMAL); } /* * ekg_getch() * * czeka na wciśnięcie klawisza i jeśli wkompilowano obsługę pythona, * przekazuje informację o zdarzeniu do skryptu. * * - meta - przedrostek klawisza. * * zwraca kod klawisza lub -2, jeśli należy go pominąć. */ int ekg_getch(int meta) { int ch; ch = wgetch(input); if (ch == KEY_MOUSE) { mouse_event("bevent"); return -2; } #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(keypress, "(ii)", meta, ch) { int dummy; PYTHON_HANDLE_RESULT("ii", &dummy, &ch) { } } PYTHON_HANDLE_FOOTER() if (python_handle_result == 0 || python_handle_result == 2) ch = -2; #endif if (ui_ncurses_beeping) { ui_ncurses_beeping = 0; ui_event("xterm_update"); } return ch; } static void binding_backward_word(const char *arg) { while (line_index > 0 && line[line_index - 1] == ' ') line_index--; while (line_index > 0 && line[line_index - 1] != ' ') line_index--; } static void binding_forward_word(const char *arg) { while (line_index < strlen(line) && line[line_index] == ' ') line_index++; while (line_index < strlen(line) && line[line_index] != ' ') line_index++; } static void binding_kill_word(const char *arg) { char *p = line + line_index; int eaten = 0; while (*p && *p == ' ') { p++; eaten++; } while (*p && *p != ' ') { p++; eaten++; } memmove(line + line_index, line + line_index + eaten, strlen(line) - line_index - eaten + 1); } static void binding_toggle_input(const char *arg) { if (input_size == 1) { input_size = 5; update_input(); } else { string_t s = string_init(""); char *tmp; int i; for (i = 0; lines[i]; i++) { if (!strcmp(lines[i], "") && !lines[i + 1]) break; string_append(s, lines[i]); if (lines[i + 1]) string_append(s, "\r\n"); } line = string_free(s, 0); tmp = xstrdup(line); history[0] = line; input_size = 1; update_input(); command_exec(window_current->target, tmp, 0); xfree(tmp); } } static void binding_cancel_input(const char *arg) { if (input_size == 5) { input_size = 1; update_input(); } } static void binding_backward_delete_char(const char *arg) { if (lines && line_index == 0 && lines_index > 0 && strlen(lines[lines_index]) + strlen(lines[lines_index - 1]) < LINE_MAXLEN) { int i; line_index = strlen(lines[lines_index - 1]); strlcat(lines[lines_index - 1], lines[lines_index], LINE_MAXLEN); xfree(lines[lines_index]); for (i = lines_index; i < array_count(lines); i++) lines[i] = lines[i + 1]; lines = xrealloc(lines, (array_count(lines) + 1) * sizeof(char*)); lines_index--; lines_adjust(); return; } if (strlen(line) > 0 && line_index > 0) { memmove(line + line_index - 1, line + line_index, LINE_MAXLEN - line_index); line[LINE_MAXLEN - 1] = 0; line_index--; } } static void binding_kill_line(const char *arg) { line[line_index] = 0; } static void binding_yank(const char *arg) { if (yanked && strlen(yanked) + strlen(line) + 1 < LINE_MAXLEN) { memmove(line + line_index + strlen(yanked), line + line_index, LINE_MAXLEN - line_index - strlen(yanked)); memcpy(line + line_index, yanked, strlen(yanked)); line_index += strlen(yanked); } } static void binding_delete_char(const char *arg) { if (line_index == strlen(line) && lines_index < array_count(lines) - 1 && strlen(line) + strlen(lines[lines_index + 1]) < LINE_MAXLEN) { int i; strlcat(line, lines[lines_index + 1], LINE_MAXLEN); xfree(lines[lines_index + 1]); for (i = lines_index + 1; i < array_count(lines); i++) lines[i] = lines[i + 1]; lines = xrealloc(lines, (array_count(lines) + 1) * sizeof(char*)); lines_adjust(); return; } if (line_index < strlen(line)) { memmove(line + line_index, line + line_index + 1, LINE_MAXLEN - line_index - 1); line[LINE_MAXLEN - 1] = 0; } } static void binding_accept_line(const char *arg) { if (lines) { int i; lines = xrealloc(lines, (array_count(lines) + 2) * sizeof(char*)); for (i = array_count(lines); i > lines_index; i--) lines[i + 1] = lines[i]; lines[lines_index + 1] = xmalloc(LINE_MAXLEN); strlcpy(lines[lines_index + 1], line + line_index, LINE_MAXLEN); line[line_index] = 0; line_index = 0; line_start = 0; lines_index++; lines_adjust(); return; } command_exec(window_current->target, line, 0); if (strcmp(line, "")) { if (history[0] != line) xfree(history[0]); history[0] = xstrdup(line); xfree(history[HISTORY_MAX - 1]); memmove(&history[1], &history[0], sizeof(history) - sizeof(history[0])); } else { if (config_enter_scrolls) print("none", ""); } history[0] = line; history_index = 0; line[0] = 0; line_adjust(); } static void binding_line_discard(const char *arg) { xfree(yanked); yanked = strdup(line); line[0] = 0; line_adjust(); if (lines && lines_index < array_count(lines) - 1) { int i; xfree(lines[lines_index]); for (i = lines_index; i < array_count(lines); i++) lines[i] = lines[i + 1]; lines = xrealloc(lines, (array_count(lines) + 1) * sizeof(char*)); lines_adjust(); } } static void binding_quoted_insert(const char *arg) { int ch; ekg_wait_for_key(); ch = ekg_getch('V' - 64); /* XXX */ if (ch < 0) return; if (strlen(line) >= LINE_MAXLEN - 1) return; memmove(line + line_index + 1, line + line_index, LINE_MAXLEN - line_index - 1); line[line_index++] = ch; } static void binding_word_rubout(const char *arg) { char *p; int eaten = 0; xfree(yanked); p = line + line_index; while (p > line && xisspace(*(p-1))) { p--; eaten++; } if (p > line) { while (p > line && !xisspace(*(p-1))) { p--; eaten++; } } yanked = xmalloc(eaten + 1); strlcpy(yanked, p, eaten + 1); memmove(p, line + line_index, strlen(line) - line_index + 1); line_index -= eaten; } static void binding_complete(const char *arg) { if (!lines) complete(&line_start, &line_index); else { int i, count = 8 - (line_index % 8); if (strlen(line) + count >= LINE_MAXLEN - 1) return; memmove(line + line_index + count, line + line_index, LINE_MAXLEN - line_index - count); for (i = line_index; i < line_index + count; i++) line[i] = ' '; line_index += count; } } static void binding_backward_char(const char *arg) { if (lines) { if (line_index > 0) line_index--; else { if (lines_index > 0) { lines_index--; lines_adjust(); line_adjust(); } } return; } if (line_index > 0) line_index--; } static void binding_forward_char(const char *arg) { if (lines) { if (line_index < strlen(line)) line_index++; else { if (lines_index < array_count(lines) - 1) { lines_index++; line_index = 0; line_start = 0; } lines_adjust(); } return; } if (line_index < strlen(line)) line_index++; } static void binding_end_of_line(const char *arg) { line_adjust(); } static void binding_beginning_of_line(const char *arg) { line_index = 0; line_start = 0; } static void binding_previous_history(const char *arg) { if (lines) { if (lines_index - lines_start == 0) if (lines_start) lines_start--; if (lines_index) lines_index--; lines_adjust(); return; } if (history[history_index + 1]) { if (history_index == 0) history[0] = xstrdup(line); history_index++; strlcpy(line, history[history_index], LINE_MAXLEN); line_adjust(); } } static void binding_next_history(const char *arg) { if (lines) { if (lines_index - line_start == 4) if (lines_index < array_count(lines) - 1) lines_start++; if (lines_index < array_count(lines) - 1) lines_index++; lines_adjust(); return; } if (history_index > 0) { history_index--; strlcpy(line, history[history_index], LINE_MAXLEN); line_adjust(); if (history_index == 0) { if (history[0] != line) { xfree(history[0]); history[0] = line; } } } } static void binding_backward_page(const char *arg) { int lines; if (config_backlog_overlap < window_current->height) lines = window_current->height - config_backlog_overlap; else lines = window_current->height; window_current->start -= lines; if (window_current->start < 0) window_current->start = 0; window_redraw(window_current); } static void binding_forward_page(const char *arg) { int lines; if (config_backlog_overlap < window_current->height) lines = window_current->height - config_backlog_overlap; else lines = window_current->height; window_current->start += lines; if (window_current->start > window_current->lines_count - window_current->height + window_current->overflow) window_current->start = window_current->lines_count - window_current->height + window_current->overflow; if (window_current->start < 0) window_current->start = 0; if (window_current->start == window_current->lines_count - window_current->height + window_current->overflow) { window_current->more = 0; update_statusbar(0); } window_redraw(window_current); } static void binding_ignore_query(const char *arg) { char *tmp; if (!window_current->target) return; tmp = saprintf("/ignore %s", window_current->target); command_exec(window_current->target, tmp, 0); xfree(tmp); } static void binding_quick_list_wrapper(const char *arg) { binding_quick_list(0, 0); } static void binding_toggle_contacts_wrapper(const char *arg) { binding_toggle_contacts(0, 0); } static void binding_next_contacts_group(const char *arg) { contacts_group_index++; contacts_update(NULL); window_commit(); } static void binding_contacts_scrolldown(const char *arg) { if (contacts_offset < contacts_count) { contacts_offset++; contacts_update(NULL); window_commit(); } } static void binding_contacts_scrollup(const char *arg) { if (contacts_offset) { contacts_offset--; contacts_update(NULL); window_commit(); } } static void binding_ui_ncurses_debug_toggle(const char *arg) { if (++ui_ncurses_debug > 2) ui_ncurses_debug = 0; update_statusbar(1); } #ifdef WITH_ASPELL /* * funkcja sprawdzajaca pisownię. */ static void spellcheck(const char *line, char *checked) { const char *start, *line_start; if (!line || *line == '/') return; line_start = line; while (*line) { if (!isalpha_pl_PL(*line)) { line++; continue; } if (!strncmp(line, "http://", 7)) { line += 7; while (!strchr(" \t\r\n", *line)) line++; continue; } if (!strncmp(line, "ftp://", 6)) { line += 6; while (!strchr(" \t\r\n", *line)) line++; continue; } start = line; while (isalpha_pl_PL(*line)) line++; #if 0 gg_debug(GG_DEBUG_MISC, "checking: %d, %s\n", line - start, start); #endif if (aspell_speller_check(spell_checker, start, line - start) == 0) memset(&checked[start - line_start], ASPELLBADCHAR, line - start); } } #endif /* * ui_ncurses_loop() * * główna pętla interfejsu. */ static void ui_ncurses_loop() { line = xmalloc(LINE_MAXLEN); #ifdef WITH_ASPELL aspell_line = xmalloc(LINE_MAXLEN); #endif strlcpy(line, "", LINE_MAXLEN); history[0] = line; for (;;) { struct binding *b = NULL; int ch; ekg_wait_for_key(); if (ui_need_refresh) { ui_need_refresh = 0; endwin(); refresh(); keypad(input, TRUE); /* wywoła wszystko, co potrzebne */ header_statusbar_resize(NULL); changed_backlog_size("backlog_size"); goto redraw_prompt; } ch = ekg_getch(0); if (ch == -1) /* dziwny błąd? */ continue; if (ch == -2) /* python każe ignorować */ continue; if (ch == 0) /* Ctrl-Space, głupie to */ continue; if (ch == 27) { if ((ch = ekg_getch(27)) < 0) continue; b = binding_map_meta[ch]; if (ch == 27) b = binding_map[27]; /* jeśli dostaliśmy \033O to albo mamy Alt-O, albo * pokaleczone klawisze funkcyjne (\033OP do \033OS). * ogólnie rzecz biorąc, nieciekawa sytuacja ;) */ if (ch == 'O') { int tmp = ekg_getch(ch); if (tmp >= 'P' && tmp <= 'S') b = binding_map[KEY_F(tmp - 'P' + 1)]; else if (tmp == 'H') b = binding_map[KEY_HOME]; else if (tmp == 'F') b = binding_map[KEY_END]; else if (tmp == 'M') continue; else ungetch(tmp); } if (b && b->action) { if (b->function) b->function(b->arg); else { char *tmp = saprintf("%s%s", ((b->action[0] == '/') ? "" : "/"), b->action); command_exec(window_current->target, tmp, 0); xfree(tmp); } } else { /* obsługa Ctrl-F1 - Ctrl-F12 na FreeBSD */ if (ch == '[') { ch = wgetch(input); if (ch == '4' && wgetch(input) == '~' && binding_map[KEY_END]) binding_map[KEY_END]->function(NULL); if (ch == '1' && wgetch(input) == '~' && binding_map[KEY_HOME]) binding_map[KEY_HOME]->function(NULL); if (ch >= 107 && ch <= 118) window_switch(ch - 106); } } } else { if ((b = binding_map[ch]) && b->action) { if (b->function) b->function(b->arg); else { char *tmp = saprintf("%s%s", ((b->action[0] == '/') ? "" : "/"), b->action); command_exec(window_current->target, tmp, 0); xfree(tmp); } } else if (ch < 255 && strlen(line) < LINE_MAXLEN - 1) { memmove(line + line_index + 1, line + line_index, LINE_MAXLEN - line_index - 1); line[line_index++] = ch; } } /* jeśli się coś zmieniło, wygeneruj dopełnienia na nowo */ if (!b || (b && b->function != binding_complete)) { array_free(completions); completions = NULL; } redraw_prompt: if (line_index - line_start > input->_maxx - 9 - window_current->prompt_len) line_start += input->_maxx - 19 - window_current->prompt_len; if (line_index - line_start < 10) { line_start -= input->_maxx - 19 - window_current->prompt_len; if (line_start < 0) line_start = 0; } werase(input); wattrset(input, color_pair(COLOR_WHITE, 0, COLOR_BLACK)); if (lines) { int i; for (i = 0; i < 5; i++) { unsigned char *p; int j; if (!lines[lines_start + i]) break; p = (unsigned char *) lines[lines_start + i]; #ifdef WITH_ASPELL memset(aspell_line, 0, LINE_MAXLEN); /* sprawdzamy pisownie */ if (config_aspell == 1) spellcheck(p, aspell_line); for (j = 0; j + line_start < strlen(p) && j < input->_maxx + 1; j++) { if (aspell_line[line_start + j] == ASPELLBADCHAR) /* jesli błędny to wyświetlamy podkreślony */ print_char_underlined(input, i, j, p[line_start + j]); else /* jesli jest wszystko okey to wyswietlamy normalny */ print_char(input, i, j, p[j + line_start]); } #else for (j = 0; j + line_start < strlen((char*) p) && j < input->_maxx + 1; j++) print_char(input, i, j, p[j + line_start]); #endif } wmove(input, lines_index - lines_start, line_index - line_start); } else { int i; if (window_current->prompt) mvwaddstr(input, 0, 0, window_current->prompt); #ifdef WITH_ASPELL memset(aspell_line, 0, LINE_MAXLEN); /* sprawdzamy pisownie */ if (config_aspell == 1) spellcheck(line, aspell_line); for (i = 0; i < input->_maxx + 1 - window_current->prompt_len && i < strlen(line) - line_start; i++) { if (aspell_line[line_start + i] == ASPELLBADCHAR) /* jesli błędny to wyświetlamy podkreślony */ print_char_underlined(input, 0, i + window_current->prompt_len, line[line_start + i]); else /* jesli jest wszystko okey to wyswietlamy normalny */ print_char(input, 0, i + window_current->prompt_len, line[line_start + i]); } #else for (i = 0; i < input->_maxx + 1 - window_current->prompt_len && i < strlen(line) - line_start; i++) print_char(input, 0, i + window_current->prompt_len, line[line_start + i]); #endif wattrset(input, color_pair(COLOR_BLACK, 1, COLOR_BLACK)); if (line_start > 0) mvwaddch(input, 0, window_current->prompt_len, '<'); if (strlen(line) - line_start > input->_maxx + 1 - window_current->prompt_len) mvwaddch(input, 0, input->_maxx, '>'); wattrset(input, color_pair(COLOR_WHITE, 0, COLOR_BLACK)); wmove(input, 0, line_index - line_start + window_current->prompt_len); } window_commit(); } } static void window_next() { struct window *next = NULL; int passed = 0; list_t l; for (l = windows; l; l = l->next) { if (l->data == window_current) passed = 1; if (passed && l->next) { struct window *w = l->next->data; if (!w->floating) { next = w; break; } } } if (!next) next = window_find("__status"); window_switch(next->id); } static void window_prev() { struct window *prev = NULL; list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->floating) continue; if (w == window_current && l != windows) break; prev = l->data; } if (!prev->id) for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->floating) prev = l->data; } window_switch(prev->id); } /* * window_kill() * * usuwa podane okno. */ void window_kill(struct window *w, int quiet) { int id = w->id; if (quiet) goto cleanup; if (id == 1 && w->target) { printq("query_finished", window_current->target); xfree(window_current->target); xfree(window_current->prompt); window_current->target = NULL; window_current->prompt = NULL; window_current->prompt_len = 0; return; } if (id == 1) { printq("window_kill_status"); return; } if (id == 0) return; if (w == window_current) window_prev(); if (config_sort_windows) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->floating) continue; if (w->id > 1 && w->id > id) w->id--; } } cleanup: if (w == window_current) window_current = NULL; if (w->backlog) { int i; for (i = 0; i < w->backlog_size; i++) { xfree(w->backlog[i]->str); xfree(w->backlog[i]->attr); xfree(w->backlog[i]); } xfree(w->backlog); } if (w->lines) { int i; for (i = 0; i < w->lines_count; i++) xfree(w->lines[i].ts); xfree(w->lines); } xfree(w->target); xfree(w->prompt); delwin(w->window); list_remove(&windows, w, 1); window_resize(); } /* * binding_parse() * * analizuje daną akcję i wypełnia pola struct binding odpowiedzialne * za działanie. * * - b - wskaźnik wypełnianej skruktury, * - action - akcja, */ static void binding_parse(struct binding *b, const char *action) { char **args; if (!b || !action) return; b->action = xstrdup(action); args = array_make(action, " \t", 1, 1, 1); if (!args[0]) { array_free(args); return; } #define __action(x,y) \ if (!strcmp(args[0], x)) { \ b->function = y; \ b->arg = xstrdup(args[1]); \ } __action("backward-word", binding_backward_word); __action("forward-word", binding_forward_word); __action("kill-word", binding_kill_word); __action("toggle-input", binding_toggle_input); __action("cancel-input", binding_cancel_input); __action("backward-delete-char", binding_backward_delete_char); __action("beginning-of-line", binding_beginning_of_line); __action("end-of-line", binding_end_of_line); __action("delete-char", binding_delete_char); __action("backward-page", binding_backward_page); __action("forward-page", binding_forward_page); __action("kill-line", binding_kill_line); __action("yank", binding_yank); __action("accept-line", binding_accept_line); __action("line-discard", binding_line_discard); __action("quoted-insert", binding_quoted_insert); __action("word-rubout", binding_word_rubout); __action("backward-char", binding_backward_char); __action("forward-char", binding_forward_char); __action("previous-history", binding_previous_history); __action("next-history", binding_next_history); __action("complete", binding_complete); __action("quick-list", binding_quick_list_wrapper); __action("toggle-contacts", binding_toggle_contacts_wrapper); __action("next-contacts-group", binding_next_contacts_group); __action("ignore-query", binding_ignore_query); __action("ui-ncurses-debug-toggle", binding_ui_ncurses_debug_toggle); __action("contacts-scroll-up", binding_contacts_scrollup); __action("contacts-scroll-down", binding_contacts_scrolldown); #undef __action array_free(args); } /* * binding_key() * * analizuje nazwę klawisza i wpisuje akcję do odpowiedniej mapy. * * 0/-1. */ int binding_key(struct binding *b, const char *key, int add) { if (!strncasecmp(key, "Alt-", 4)) { unsigned char ch; if (!strcasecmp(key + 4, "Enter")) { b->key = xstrdup("Alt-Enter"); if (add) binding_map_meta[13] = list_add(&bindings, b, sizeof(struct binding)); return 0; } if (!strcasecmp(key + 4, "Backspace")) { b->key = xstrdup("Alt-Backspace"); if (add) { binding_map_meta[KEY_BACKSPACE] = list_add(&bindings, b, sizeof(struct binding)); binding_map_meta[127] = binding_map_meta[KEY_BACKSPACE]; } return 0; } if (strlen(key) != 5) return -1; ch = xtoupper(key[4]); b->key = saprintf("Alt-%c", ch); if (add) { binding_map_meta[ch] = list_add(&bindings, b, sizeof(struct binding)); if (xisalpha(ch)) binding_map_meta[xtolower(ch)] = binding_map_meta[ch]; } return 0; } if (!strncasecmp(key, "Ctrl-", 5)) { unsigned char ch; if (strlen(key) != 6 || !xisalpha(key[5])) return -1; ch = xtoupper(key[5]); b->key = saprintf("Ctrl-%c", ch); if (add) binding_map[ch - 64] = list_add(&bindings, b, sizeof(struct binding)); return 0; } if (xtoupper(key[0]) == 'F' && atoi(key + 1)) { int f = atoi(key + 1); if (f < 1 || f > 24) return -1; b->key = saprintf("F%d", f); if (add) binding_map[KEY_F(f)] = list_add(&bindings, b, sizeof(struct binding)); return 0; } #define __key(x, y, z) \ if (!strcasecmp(key, x)) { \ b->key = xstrdup(x); \ if (add) { \ binding_map[y] = list_add(&bindings, b, sizeof(struct binding)); \ if (z) \ binding_map[z] = binding_map[y]; \ } \ return 0; \ } __key("Enter", 13, 0); __key("Escape", 27, 0); __key("Home", KEY_HOME, KEY_FIND); __key("End", KEY_END, KEY_SELECT); binding_map[KEY_LL] = binding_map[KEY_END]; __key("Delete", KEY_DC, 0); __key("Backspace", KEY_BACKSPACE, 127); __key("Tab", 9, 0); __key("Left", KEY_LEFT, 0); __key("Right", KEY_RIGHT, 0); __key("Up", KEY_UP, 0); __key("Down", KEY_DOWN, 0); __key("PageUp", KEY_PPAGE, 0); __key("PageDown", KEY_NPAGE, 0); #undef __key return -1; } /* * binding_add() * * przypisuje danemu klawiszowi akcję. * * - key - opis klawisza, * - action - akcja, * - internal - czy to wewnętrzna akcja interfejsu? * - quiet - czy być cicho i nie wyświetlać niczego? */ static void binding_add(const char *key, const char *action, int internal, int quiet) { struct binding b, *c = NULL; list_t l; if (!key || !action) return; memset(&b, 0, sizeof(b)); b.internal = internal; for (l = bindings; l; l = l->next) { struct binding *d = l->data; if (!strcasecmp(key, d->key)) { if (d->internal) { c = d; break; } printq("bind_seq_exist", d->key); return; } } binding_parse(&b, action); if (internal) { b.default_action = xstrdup(b.action); b.default_function = b.function; b.default_arg = xstrdup(b.arg); } if (binding_key(&b, key, (c) ? 0 : 1)) { printq("bind_seq_incorrect", key); xfree(b.action); xfree(b.arg); xfree(b.default_action); xfree(b.default_arg); xfree(b.key); } else { printq("bind_seq_add", b.key); if (c) { xfree(c->action); c->action = b.action; xfree(c->arg); c->arg = b.arg; c->function = b.function; xfree(b.default_action); xfree(b.default_arg); xfree(b.key); c->internal = 0; } if (!in_autoexec) config_changed = 1; } } /* * binding_delete() * * usuwa akcję z danego klawisza. */ static void binding_delete(const char *key, int quiet) { list_t l; if (!key) return; for (l = bindings; l; l = l->next) { struct binding *b = l->data; int i; if (!b->key || strcasecmp(key, b->key)) continue; if (b->internal) { printq("bind_seq_incorrect", key); return; } xfree(b->action); xfree(b->arg); if (b->default_action) { b->action = xstrdup(b->default_action); b->arg = xstrdup(b->default_arg); b->function = b->default_function; b->internal = 1; } else { xfree(b->key); for (i = 0; i < KEY_MAX + 1; i++) { if (binding_map[i] == b) binding_map[i] = NULL; if (binding_map_meta[i] == b) binding_map_meta[i] = NULL; } list_remove(&bindings, b, 1); } config_changed = 1; printq("bind_seq_remove", key); return; } printq("bind_seq_incorrect", key); } /* * ui_ncurses_event() * * obsługa zdarzeń. */ static int ui_ncurses_event(const char *event, ...) { va_list ap; va_start(ap, event); if (!event) return 0; if (!strcmp(event, "xterm_update") && getenv("TERM") && !strncmp(getenv("TERM"), "xterm", 5) && !getenv("EKG_NO_TITLE")) { char *tmp = saprintf("\033]2;ekg (%d)%s\007", config_uin, ui_ncurses_beeping ? " BEEP!" : ""); write(1, tmp, strlen(tmp)); xfree(tmp); } if (!strcasecmp(event, "refresh_time")) goto cleanup; if (!strcasecmp(event, "check_mail")) check_mail(); if (!strcasecmp(event, "commit")) window_commit(); if (!strcasecmp(event, "printat")) { char *target = va_arg(ap, char*); int id = va_arg(ap, int), x = va_arg(ap, int), y = va_arg(ap, int); char *text = va_arg(ap, char*); struct window *w = NULL; if (target) w = window_find(target); if (id) { list_t l; for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->id == id) { w = v; break; } } } if (w && text) window_printat(w->window, x, y, text, NULL, COLOR_WHITE, 0, COLOR_BLACK, 0); } if (!strcmp(event, "variable_changed")) { char *name = va_arg(ap, char*); if (!strcasecmp(name, "sort_windows") && config_sort_windows) { list_t l; int id = 2; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->floating) continue; if (w->id > 1) w->id = id++; } } if (!strcasecmp(name, "timestamp")) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; window_backlog_split(w, 1, 0); } window_resize(); } if (!strcasecmp(name, "backlog_size")) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; int i; if (w->backlog_size <= config_backlog_size) continue; for (i = config_backlog_size; i < w->backlog_size; i++) { xfree(w->backlog[i]->str); xfree(w->backlog[i]->attr); xfree(w->backlog[i]); } w->backlog_size = config_backlog_size; w->backlog = xrealloc(w->backlog, w->backlog_size * sizeof(fstring_t)); window_backlog_split(w, 1, 0); } } if (!strncasecmp(name, "contacts", 8)) contacts_changed(); if (!strncasecmp(name, "mouse", 5)) mouse_event(config_mouse ? "enable" : "disable"); } if (!strcmp(event, "conference_rename")) { char *oldname = va_arg(ap, char*), *newname = va_arg(ap, char*); list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->target && !strcasecmp(w->target, oldname)) { xfree(w->target); xfree(w->prompt); w->target = xstrdup(newname); w->prompt = format_string(format_find("ncurses_prompt_query"), newname); w->prompt_len = strlen(w->prompt); } } goto cleanup; } if (!strcmp(event, "userlist_changed")) { const char *p1 = va_arg(ap, char*), *p2 = va_arg(ap, char*); list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->target || !p1 || strcasecmp(w->target, p1)) continue; xfree(w->target); w->target = xstrdup(p2); xfree(w->prompt); w->prompt = format_string(format_find("ncurses_prompt_query"), w->target); w->prompt_len = strlen(w->prompt); } goto cleanup; } if (!strcmp(event, "command")) { int quiet = va_arg(ap, int); char *command = va_arg(ap, char*); if (!strcasecmp(command, "bind")) { char *p1 = va_arg(ap, char*), *p2 = va_arg(ap, char*), *p3 = va_arg(ap, char*); if (match_arg(p1, 'a', "add", 2)) { if (!p2 || !p3) printq("not_enough_params", "bind"); else binding_add(p2, p3, 0, quiet); } else if (match_arg(p1, 'd', "delete", 2)) { if (!p2) printq("not_enough_params", "bind"); else binding_delete(p2, quiet); } else if (match_arg(p1, 'L', "list-default", 5)) { binding_list(quiet, p2, 1); } else { if (match_arg(p1, 'l', "list", 2)) binding_list(quiet, p2, 0); else binding_list(quiet, p1, 0); } goto cleanup; } if (!strcasecmp(command, "find")) { char *tmp = NULL; if (window_current->target) { struct userlist *u = userlist_find(0, window_current->target); struct conference *c = conference_find(window_current->target); int uin; if (u && u->uin) tmp = saprintf("/find %d", u->uin); if (c && c->name) tmp = saprintf("/conference --find %s", c->name); if (!u && !c && (uin = atoi(window_current->target))) tmp = saprintf("/find %d", uin); } if (!tmp) tmp = saprintf("/find %d", config_uin); command_exec(window_current->target, tmp, 0); xfree(tmp); goto cleanup; } if (!strcasecmp(command, "query-current")) { uin_t *param = va_arg(ap, uin_t*); if (window_current->target) *param = get_uin(window_current->target); else *param = 0; goto cleanup; } if (!strcasecmp(command, "query-nicks")) { char ***param = va_arg(ap, char***); list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->floating || !w->target) continue; array_add(param, xstrdup(w->target)); } goto cleanup; } if (!strcasecmp(command, "query")) { char *param = va_arg(ap, char*); if (!param && !window_current->target) goto cleanup; if (param) { struct window *w; if ((w = window_find(param))) { window_switch(w->id); goto cleanup; } if ((config_make_window & 3) == 1) { list_t l; for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->id < 2 || v->floating || v->target) continue; w = v; break; } if (!w) w = window_new(param, 0); window_switch(w->id); } if ((config_make_window & 3) == 2) { w = window_new(param, 0); window_switch(w->id); } xfree(window_current->target); xfree(window_current->prompt); window_current->target = xstrdup(param); window_current->prompt = format_string(format_find("ncurses_prompt_query"), param); window_current->prompt_len = strlen(window_current->prompt); if (!quiet) { print_window(param, 0, "query_started", param); print_window(param, 0, "query_started_window", param); } } else { const char *f = format_find("ncurses_prompt_none"); printq("query_finished", window_current->target); xfree(window_current->target); xfree(window_current->prompt); window_current->target = NULL; window_current->prompt = NULL; window_current->prompt_len = 0; if (strcmp(f, "")) { window_current->prompt = xstrdup(f); window_current->prompt_len = strlen(f); } } goto cleanup; } if (!strcasecmp(command, "window")) { char *p1 = va_arg(ap, char*), *p2 = va_arg(ap, char*); if (!p1 || !strcasecmp(p1, "list")) { int num = p2 ? atoi(p2) : 0; list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id && (!p2 || w->id == num)) { if (w->target) { if (!w->floating) printq("window_list_query", itoa(w->id), w->target); else printq("window_list_floating", itoa(w->id), itoa(w->left), itoa(w->top), itoa(w->width), itoa(w->height), w->target); } else printq("window_list_nothing", itoa(w->id)); } } goto cleanup; } if (!strcasecmp(p1, "active")) { list_t l; int idlow = 0, idhigh = 0; // w->act == 0 - brak aktywności // w->act == 1 - aktywność mała // w->act == 2 - aktywność duża // przelatujemy przez wszystkie aktywności, zapisujemy małą // i dużą. jeżeli była jakaś duża to wykorzystujemy dużą, // jeżeli nie, to wykorzystujemy małą. for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->act && !w->floating && w->id) { if (w->act == 1) { if (!idlow) idlow = w->id; } else if (w->act == 2) { if (!idhigh) idhigh = w->id; } if (idlow && idhigh) break; } } if (idhigh) window_switch(idhigh); else if (idlow) window_switch(idlow); goto cleanup; } if (!strcasecmp(p1, "oldest")) { list_t l; int id = 0; time_t id_time = time(NULL); for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->act && !w->floating && w->id && w->first_act_time < id_time) { id = w->id; id_time = w->first_act_time; } } if (id) window_switch(id); goto cleanup; } if (!strcasecmp(p1, "new")) { struct window *w = window_new(p2, 0); if (!w->floating) window_switch(w->id); goto cleanup; } if (!strcasecmp(p1, "switch")) { if (!p2) { printq("not_enough_params", "window"); goto cleanup; } window_switch(atoi(p2)); goto cleanup; } if (!strcasecmp(p1, "last")) { window_switch(window_last_id); goto cleanup; } if (!strcasecmp(p1, "kill")) { struct window *w = window_current; if (p2) { list_t l; for (w = NULL, l = windows; l; l = l->next) { struct window *ww = l->data; if (ww->id == atoi(p2)) { w = ww; break; } } if (!w) { printq("window_noexist"); goto cleanup; } } window_kill(w, 0); goto cleanup; } if (!strcasecmp(p1, "next")) { window_next(); goto cleanup; } if (!strcasecmp(p1, "prev")) { window_prev(); goto cleanup; } if (!strcasecmp(p1, "move")) { struct window *w = NULL; char **argv; list_t l; if (!p2) { printq("not_enough_params", "window"); goto cleanup; } argv = array_make(p2, " ,", 3, 0, 0); if (array_count(argv) < 3) { printq("not_enough_params", "window"); array_free(argv); goto cleanup; } for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->id == atoi(argv[0])) { w = v; break; } } if (!w) { printq("window_noexist"); array_free(argv); goto cleanup; } switch (argv[1][0]) { case '-': w->left += atoi(argv[1]); break; case '+': w->left += atoi(argv[1] + 1); break; default: w->left = atoi(argv[1]); } switch (argv[2][0]) { case '-': w->top += atoi(argv[2]); break; case '+': w->top += atoi(argv[2] + 1); break; default: w->top = atoi(argv[2]); } array_free(argv); if (w->left + w->width > stdscr->_maxx + 1) w->left = stdscr->_maxx + 1 - w->width; if (w->top + w->height > stdscr->_maxy + 1) w->top = stdscr->_maxy + 1 - w->height; if (w->floating) mvwin(w->window, w->top, w->left); touchwin(window_current->window); window_refresh(); doupdate(); goto cleanup; } if (!strcasecmp(p1, "resize")) { struct window *w = NULL; char **argv; list_t l; if (!p2) { printq("not_enough_params", "window"); goto cleanup; } argv = array_make(p2, " ,", 3, 0, 0); if (array_count(argv) < 3) { printq("not_enough_params", "window"); array_free(argv); goto cleanup; } for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->id == atoi(argv[0])) { w = v; break; } } if (!w) { printq("window_noexist"); array_free(argv); goto cleanup; } switch (argv[1][0]) { case '-': w->width += atoi(argv[1]); break; case '+': w->width += atoi(argv[1] + 1); break; default: w->width = atoi(argv[1]); } switch (argv[2][0]) { case '-': w->height += atoi(argv[2]); break; case '+': w->height += atoi(argv[2] + 1); break; default: w->height = atoi(argv[2]); } array_free(argv); if (w->floating) { wresize(w->window, w->height, w->width); window_backlog_split(w, 1, 0); window_redraw(w); touchwin(window_current->window); window_commit(); } goto cleanup; } if (!strcasecmp(p1, "refresh")) { window_floating_update(0); wrefresh(curscr); goto cleanup; } if (!strcasecmp(p1, "clear")) { window_clear(window_current, 0); window_commit(); window_current->more = 0; goto cleanup; } if (!strcasecmp(p1, "dump")) { FILE *f; int i; if (!p2) { printq("not_enough_params", "window"); goto cleanup; } if (!(f = fopen(p2, "a"))) { printq("window_dump_error", p2); goto cleanup; } for (i = window_current->backlog_size - 1; i >= 0; i--) { char ts[100]; strftime(ts, sizeof(ts), (config_timestamp) ? config_timestamp : "%H:%M ", localtime((time_t*) (&window_current->backlog[i]->ts))); fprintf(f, "%s%s\n", ts, window_current->backlog[i]->str); } if (fclose(f) == EOF) printq("window_dump_error", p2); else printq("window_dump_done"); goto cleanup; } if (!strcasecmp(p1, "swap")) { char **argv; struct window *w[2] = {NULL, NULL}; struct window tmpwin; int tmpid; int i; if (!p2) { printq("not_enough_params", "window"); goto cleanup; } argv = array_make(p2, " ,", 2, 0, 0); if (array_count(argv) < 2) { printq("not_enough_params", "window"); array_free(argv); goto cleanup; } for (i = 0; i < 2; ++i) { list_t l; for (l = windows; l; l = l->next) { struct window *v = l->data; if (v->id == atoi(argv[i])) { w[i] = v; break; } } } array_free(argv); if (!w[0] || !w[1]) { printq("window_noexist"); goto cleanup; } /* pozwalamy na zmiane okna statusu, to nie jest blad */ if (w[0] == w[1] || !w[0]->id || !w[1]->id || (w[0]->target && (!strcasecmp(w[0]->target, "__contacts") || !strcasecmp(w[0]->target, "__debug"))) || (w[1]->target && (!strcasecmp(w[1]->target, "__contacts") || !strcasecmp(w[1]->target, "__debug")))) { printq("invalid_params", "window"); goto cleanup; } tmpid = w[0]->id; w[0]->id = w[1]->id; w[1]->id = tmpid; /* podmiana takze zawartosci struktur zeby /window list dzialalo dobrze */ memcpy(&tmpwin, w[0], sizeof(struct window)); memcpy(w[0], w[1], sizeof(struct window)); memcpy(w[1], &tmpwin, sizeof(struct window)); /* jezeli jedno z zamienianych okien bylo oknem aktualnym to przelaczamy sie do niego */ if (window_current == w[0]) window_switch(w[1]->id); else if (window_current == w[1]) window_switch(w[0]->id); printq("window_swapped", itoa(w[0]->id), itoa(w[1]->id)); goto cleanup; } printq("invalid_params", "window"); } } if (!strcmp(event, "get_window_list")) { int *windowlist = va_arg(ap, int*); int start = va_arg(ap, int), stop = va_arg(ap, int); list_t l; int index = 0; for (l = windows; l; l = l->next) { struct window *w = l->data; if ((w->id >= start) && (w->id <= stop)) windowlist[++index] = w->id; } windowlist[0] = index; goto cleanup; } cleanup: va_end(ap); contacts_update(NULL); update_statusbar(1); return 0; } /* * header_statusbar_resize() * * zmienia rozmiar paska stanu i/lub nagłówka okna. */ void header_statusbar_resize(const char *name) { if (!status) return; if (config_header_size < 0) config_header_size = 0; if (config_header_size > 5) config_header_size = 5; if (config_statusbar_size < 1) config_statusbar_size = 1; if (config_statusbar_size > 5) config_statusbar_size = 5; if (config_header_size) { if (!header) { struct mouse_area_t a; header = newwin(config_header_size, stdscr->_maxx + 1, 0, 0); a.name = "header"; a.start.x = 0; a.start.y = 0; a.size.x = stdscr->_maxx + 1; a.size.y = config_header_size; a.bevents = NULL; mouse_bevent_add(&a, BUTTON1_CLICKED, mouse_bevent_header); mouse_bevent_add(&a, BUTTON1_DOUBLE_CLICKED, mouse_bevent_header); mouse_area_add(&a); } else { wresize(header, config_header_size, stdscr->_maxx + 1); mouse_area_resize("header", config_header_size, stdscr->_maxx + 1); } update_header(0); } if (!config_header_size && header) { delwin(header); mouse_area_del("header"); header = NULL; } window_resize(); wresize(status, config_statusbar_size, stdscr->_maxx + 1); mvwin(status, stdscr->_maxy + 1 - input_size - config_statusbar_size, 0); mouse_area_resize("status", config_statusbar_size, stdscr->_maxx + 1); mouse_area_move("status", stdscr->_maxy + 1 - input_size - config_statusbar_size, 0); update_statusbar(0); window_commit(); } /* * binding_default() * * ustawia lub przywraca domyślne ustawienia przypisanych klawiszy. */ static void binding_default() { #ifndef GG_DEBUG_DISABLE binding_add("Alt-`", "/window switch 0", 1, 1); #endif binding_add("Alt-1", "/window switch 1", 1, 1); binding_add("Alt-2", "/window switch 2", 1, 1); binding_add("Alt-3", "/window switch 3", 1, 1); binding_add("Alt-4", "/window switch 4", 1, 1); binding_add("Alt-5", "/window switch 5", 1, 1); binding_add("Alt-6", "/window switch 6", 1, 1); binding_add("Alt-7", "/window switch 7", 1, 1); binding_add("Alt-8", "/window switch 8", 1, 1); binding_add("Alt-9", "/window switch 9", 1, 1); binding_add("Alt-0", "/window switch 10", 1, 1); binding_add("Alt-Q", "/window switch 11", 1, 1); binding_add("Alt-W", "/window switch 12", 1, 1); binding_add("Alt-E", "/window switch 13", 1, 1); binding_add("Alt-R", "/window switch 14", 1, 1); binding_add("Alt-T", "/window switch 15", 1, 1); binding_add("Alt-Y", "/window switch 16", 1, 1); binding_add("Alt-U", "/window switch 17", 1, 1); binding_add("Alt-I", "/window switch 18", 1, 1); binding_add("Alt-O", "/window switch 19", 1, 1); binding_add("Alt-P", "/window switch 20", 1, 1); binding_add("Alt-K", "/window kill", 1, 1); binding_add("Alt-N", "/window new", 1, 1); binding_add("Alt-A", "/window active", 1, 1); binding_add("Alt-S", "/window oldest", 1, 1); binding_add("Alt-G", "ignore-query", 1, 1); binding_add("Alt-B", "backward-word", 1, 1); binding_add("Alt-F", "forward-word", 1, 1); binding_add("Alt-D", "kill-word", 1, 1); binding_add("Alt-Enter", "toggle-input", 1, 1); binding_add("Escape", "cancel-input", 1, 1); binding_add("Ctrl-N", "/window next", 1, 1); binding_add("Ctrl-P", "/window prev", 1, 1); binding_add("Backspace", "backward-delete-char", 1, 1); binding_add("Ctrl-H", "backward-delete-char", 1, 1); binding_add("Ctrl-A", "beginning-of-line", 1, 1); binding_add("Home", "beginning-of-line", 1, 1); binding_add("Ctrl-D", "delete-char", 1, 1); binding_add("Delete", "delete-char", 1, 1); binding_add("Ctrl-E", "end-of-line", 1, 1); binding_add("End", "end-of-line", 1, 1); binding_add("Ctrl-K", "kill-line", 1, 1); binding_add("Ctrl-Y", "yank", 1, 1); binding_add("Enter", "accept-line", 1, 1); binding_add("Ctrl-M", "accept-line", 1, 1); binding_add("Ctrl-U", "line-discard", 1, 1); binding_add("Ctrl-V", "quoted-insert", 1, 1); binding_add("Ctrl-W", "word-rubout", 1, 1); binding_add("Alt-Backspace", "word-rubout", 1, 1); binding_add("Ctrl-L", "/window refresh", 1, 1); binding_add("Tab", "complete", 1, 1); binding_add("Right", "forward-char", 1, 1); binding_add("Left", "backward-char", 1, 1); binding_add("Up", "previous-history", 1, 1); binding_add("Down", "next-history", 1, 1); binding_add("PageUp", "backward-page", 1, 1); binding_add("Ctrl-F", "backward-page", 1, 1); binding_add("PageDown", "forward-page", 1, 1); binding_add("Ctrl-G", "forward-page", 1, 1); binding_add("F1", "/help", 1, 1); binding_add("F2", "quick-list", 1, 1); binding_add("F3", "toggle-contacts", 1, 1); binding_add("F4", "next-contacts-group", 1, 1); #ifndef GG_DEBUG_DISABLE binding_add("F12", "/window switch 0", 1, 1); #endif binding_add("F11", "ui-ncurses-debug-toggle", 1, 1); binding_add("Alt-Z", "contacts-scroll-up", 1, 1); binding_add("Alt-X", "contacts-scroll-down", 1, 1); } ekg-1.9~pre+r2855/src/ui-none.c000066400000000000000000000024061174410337000161260ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "stuff.h" #include "ui.h" static void loop() { if (batch_line) while (batch_line) ekg_wait_for_key(); else for (;;) ekg_wait_for_key(); } static void nop() { } static int event(const char *foo, ...) { return 0; } void ui_none_init() { int fd, dn = open("/dev/null", O_RDWR); for (fd = 0; fd < 3; fd++) { close(fd); dup2(dn, fd); } ui_postinit = nop; ui_print = nop; ui_loop = loop; ui_beep = nop; ui_event = event; ui_deinit = nop; } ekg-1.9~pre+r2855/src/ui-readline.c000066400000000000000000001071761174410337000167640ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2005 Wojtek Kaniewski * Robert J. Woźny * Paweł Maziarz * Adam Osuchowski * Wojtek Bojdoł * Piotr Domagalski * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "commands.h" #include "mail.h" #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "userlist.h" #include "vars.h" #include "xmalloc.h" /* podstawmy ewentualnie brakujące funkcje i definicje readline */ extern void rl_extend_line_buffer(int len); extern char **completion_matches(); #ifndef HAVE_RL_BIND_KEY_IN_MAP int rl_bind_key_in_map(int key, void *function, void *keymap) { return -1; } #endif #ifndef HAVE_RL_GET_SCREEN_SIZE int rl_get_screen_size(int *lines, int *columns) { #ifdef TIOCGWINSZ struct winsize ws; memset(&ws, 0, sizeof(ws)); ioctl(0, TIOCGWINSZ, &ws); *columns = ws.ws_col; *lines = ws.ws_row; #else *columns = 80; *lines = 24; #endif return 0; } #endif #ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION static char *rl_filename_completion_function() { return NULL; } #endif #ifndef HAVE_RL_SET_PROMPT int rl_set_prompt(const char *foo) { return -1; } #endif #ifndef HAVE_RL_SET_KEY int rl_set_key(const char *key, void *function, void *keymap) { return -1; } #endif struct window { int id, act; time_t act_time; char *query_nick; char *line[MAX_LINES_PER_SCREEN]; }; static int window_last_id = -1; /* deklaracje funkcji interfejsu */ static void ui_readline_loop(); static void ui_readline_print(const char *target, int separate, const char *line); static void ui_readline_beep(); static int ui_readline_event(const char *event, ...); static void ui_readline_deinit(); static void ui_readline_postinit(); static int in_readline = 0, no_prompt = 0, pager_lines = -1, screen_lines = 24, screen_columns = 80; static list_t windows = NULL; struct window *window_current = NULL; /* kod okienek napisany jest na podstawie ekg-windows nilsa */ static struct window *window_add(); static int window_remove(int id, int quiet); static int window_switch(int id, int quiet); static int window_refresh(); static int window_write(int id, const char *line); static void window_clear(); static void window_list(); static int window_make_query(const char *nick); static void window_free(); static struct window *window_find(int id); static int window_find_query(const char *qnick); static char *window_activity(); static int bind_sequence(const char *seq, const char *command, int quiet); static int bind_handler_window(int a, int key); /* * sigcont_handler() //XXX może wywalać * * osługuje powrót z tła poleceniem ,,fg'', żeby odświeżyć ekran. */ static void sigcont_handler() { rl_forced_update_display(); } /* * sigint_handler() //XXX może wywalać * * obsługuje wciśnięcie Ctrl-C. */ static void sigint_handler() { rl_delete_text(0, rl_end); rl_point = rl_end = 0; putchar('\n'); rl_forced_update_display(); } #ifdef SIGWINCH /* * sigwinch_handler() * * obsługuje zmianę rozmiaru okna. */ static void sigwinch_handler() { ui_need_refresh = 1; } #endif /* * my_getc() * * pobiera znak z klawiatury obsługując w międzyczasie sieć. */ static int my_getc(FILE *f) { ekg_wait_for_key(); if (ui_need_refresh) { ui_need_refresh = 0; rl_get_screen_size(&screen_lines, &screen_columns); if (screen_lines < 1) screen_lines = 24; if (screen_columns < 1) screen_columns = 80; ui_screen_width = screen_columns; ui_screen_height = screen_lines; } return rl_getc(f); } static char *command_generator(char *text, int state) { static int len; static list_t l; int slash = 0; if (*text == '/') { slash = 1; text++; } if (!*rl_line_buffer) { char *nick, *ret; if (state) return NULL; if (send_nicks_count < 1) return saprintf((window_current->query_nick) ? "/%s" : "%s", (config_tab_command) ? config_tab_command : "msg"); send_nicks_index = (send_nicks_count > 1) ? 1 : 0; nick = ((strchr(send_nicks[0], ' ')) ? saprintf("\"%s\"", send_nicks[0]) : xstrdup(send_nicks[0])); ret = saprintf((window_current->query_nick) ? "/%s %s" : "%s %s", (config_tab_command) ? config_tab_command : "chat", nick); xfree(nick); return ret; } if (!state) { l = commands; len = strlen(text); } for (; l; l = l->next) { struct command *c = l->data; if (!strncasecmp(text, c->name, len)) { l = l->next; return (window_current->query_nick) ? saprintf("/%s", c->name) : xstrdup(c->name); } } return NULL; } static char *known_uin_generator(char *text, int state) { static list_t l; static int len; if (!state) { l = userlist; len = strlen(text); } while (l) { struct userlist *u = l->data; l = l->next; if (u->display && !strncasecmp(text, u->display, len)) return ((strchr(u->display, ' ')) ? saprintf("\"%s\"", u->display) : xstrdup(u->display)); } return NULL; } static char *unknown_uin_generator(char *text, int state) { static int index = 0, len; if (!state) { index = 0; len = strlen(text); } while (index < send_nicks_count) if (xisdigit(send_nicks[index++][0])) if (!strncasecmp(text, send_nicks[index - 1], len)) return xstrdup(send_nicks[index - 1]); return NULL; } static char *variable_generator(char *text, int state) { static list_t l; static int len; if (!state) { l = variables; len = strlen(text); } while (l) { struct variable *v = l->data; l = l->next; if (v->type == VAR_FOREIGN || !v->ptr) continue; if (*text == '-') { if (!strncasecmp(text + 1, v->name, len - 1)) return saprintf("-%s", v->name); } else { if (!strncasecmp(text, v->name, len)) return xstrdup(v->name); } } return NULL; } static char *ignored_uin_generator(char *text, int state) { static list_t l; static int len; if (!state) { l = userlist; len = strlen(text); } while (l) { struct userlist *u = l->data; l = l->next; if (!ignored_check(u->uin)) continue; if (!u->display) { if (!strncasecmp(text, itoa(u->uin), len)) return xstrdup(itoa(u->uin)); } else { if (u->display && !strncasecmp(text, u->display, len)) return ((strchr(u->display, ' ')) ? saprintf("\"%s\"", u->display) : xstrdup(u->display)); } } return NULL; } static char *blocked_uin_generator(char *text, int state) { static list_t l; static int len; if (!state) { l = userlist; len = strlen(text); } while (l) { struct userlist *u = l->data; l = l->next; if (!group_member(u, "__blocked")) continue; if (!u->display) { if (!strncasecmp(text, itoa(u->uin), len)) return xstrdup(itoa(u->uin)); } else { if (u->display && !strncasecmp(text, u->display, len)) return ((strchr(u->display, ' ')) ? saprintf("\"%s\"", u->display) : xstrdup(u->display)); } } return NULL; } static char *dcc_generator(char *text, int state) { char *commands[] = { "close", "get", "send", "list", "resume", "rsend", "rvoice", "voice", NULL }; static int len, i; if (!state) { i = 0; len = strlen(text); } while (commands[i]) { if (!strncasecmp(text, commands[i], len)) return xstrdup(commands[i++]); i++; } return NULL; } static char *window_generator(char *text, int state) { char *commands[] = { "new", "kill", "next", "prev", "switch", "clear", "refresh", "list", "last", "active", NULL }; static int len, i; if (!state) { i = 0; len = strlen(text); } while (commands[i]) { if (!strncasecmp(text, commands[i], len)) return xstrdup(commands[i++]); i++; } return NULL; } static char *python_generator(char *text, int state) { char *commands[] = { "load", "unload", "run", "exec", "list", "restart", NULL }; static int len, i; if (!state) { i = 0; len = strlen(text); } while (commands[i]) { if (!strncasecmp(text, commands[i], len)) return xstrdup(commands[i++]); i++; } return NULL; } static char *reason_generator(char *text, int state) { static int len; if (!state) { len = strlen(text); if (config_reason && !strncasecmp(text, config_reason, len)) return xstrdup(config_reason); } return NULL; } static char *empty_generator(char *text, int state) { return NULL; } static char **my_completion(char *text, int start, int end) { char *params = NULL; int word = 0, i, abbrs = 0; CPFunction *func = known_uin_generator; list_t l; static int my_send_nicks_count = 0; if (start) { char *tmp = rl_line_buffer, *cmd = (config_tab_command) ? config_tab_command : "chat"; int slash = 0; if (*tmp == '/') { slash = 1; tmp++; } if (!strncasecmp(tmp, cmd, strlen(cmd)) && tmp[strlen(cmd)] == ' ') { int in_quote = 0; word = 0; for (i = 0; i < strlen(rl_line_buffer); i++) { if (rl_line_buffer[i] == '"') in_quote = !in_quote; if (xisspace(rl_line_buffer[i]) && !in_quote) word++; } if (word == 2 && xisspace(rl_line_buffer[strlen(rl_line_buffer) - 1])) { if (send_nicks_count != my_send_nicks_count) { my_send_nicks_count = send_nicks_count; send_nicks_index = 0; } if (send_nicks_count > 0) { char buf[100], *tmp; tmp = ((strchr(send_nicks[send_nicks_index], ' ')) ? saprintf("\"%s\"", send_nicks[send_nicks_index]) : xstrdup(send_nicks[send_nicks_index])); snprintf(buf, sizeof(buf), "%s%s %s ", (slash) ? "/" : "", cmd, tmp); xfree(tmp); send_nicks_index++; rl_extend_line_buffer(strlen(buf)); strlcpy(rl_line_buffer, buf, strlen(buf) + 1); rl_end = strlen(buf); rl_point = rl_end; rl_redisplay(); } if (send_nicks_index == send_nicks_count) send_nicks_index = 0; return NULL; } word = 0; } } if (start) { int in_quote = 0; for (i = 1; i <= start; i++) { if (rl_line_buffer[i] == '"') in_quote = !in_quote; if (xisspace(rl_line_buffer[i]) && !xisspace(rl_line_buffer[i - 1]) && !in_quote) word++; } word--; for (l = commands; l; l = l->next) { struct command *c = l->data; int len = strlen(c->name); char *cmd = (*rl_line_buffer == '/') ? rl_line_buffer + 1 : rl_line_buffer; if (!strncasecmp(cmd, c->name, len) && xisspace(cmd[len])) { params = c->params; abbrs = 1; break; } for (len = 0; cmd[len] && cmd[len] != ' '; len++); if (!strncasecmp(cmd, c->name, len)) { params = c->params; abbrs++; } else if (params && abbrs == 1) break; } if (params && abbrs == 1) { if (word >= strlen(params)) func = empty_generator; else { switch (params[word]) { case 'u': func = known_uin_generator; break; case 'U': func = unknown_uin_generator; break; case 'c': func = command_generator; break; case 's': /* XXX */ func = empty_generator; break; case 'i': func = ignored_uin_generator; break; case 'b': func = blocked_uin_generator; break; case 'v': func = variable_generator; break; case 'd': func = dcc_generator; break; case 'f': func = rl_filename_completion_function; break; case 'p': func = python_generator; break; case 'w': func = window_generator; break; case 'r': func = reason_generator; break; default: func = empty_generator; break; } } } } if (start == 0) func = command_generator; return completion_matches(text, func); } /* * ui_readline_print() * * wyświetla dany tekst na ekranie, uważając na trwające w danych chwili * readline(). */ static void ui_readline_print(const char *target, int separate, const char *xline) { int old_end = rl_end, id = 0; char *old_prompt = NULL, *line_buf = NULL; const char *p, *line = NULL; string_t s = NULL; if (target && !strcmp(target, "__debug")) return; if (config_timestamp) { string_t s = string_init(NULL); const char *p = xline; char buf[80]; struct tm *tm; time_t t; t = time(NULL); tm = localtime(&t); strftime(buf, sizeof(buf), config_timestamp, tm); string_append(s, "\033[0m"); string_append(s, buf); while (*p) { if (*p == '\n' && *(p + 1)) { string_append_c(s, '\n'); string_append(s, buf); } else string_append_c(s, *p); p++; } line = line_buf = string_free(s, 0); } else line = xline; if (config_speech_app) { int in_esc_code = 0; s = string_init(NULL); for (p = line; *p; p++) { if (*p == 27) in_esc_code = 1; /* zakładamy, że 'm' kończy eskejpową sekwencje */ if (in_esc_code && *p == 'm') { in_esc_code = 0; continue; } if (!in_esc_code) string_append_c(s, *p); } } /* znajdź odpowiednie okienko i ewentualnie je utwórz */ if (target && separate) id = window_find_query(target); if ((config_make_window & 3) > 0 && !id && strncmp(target, "__", 2) && separate) id = window_make_query(target); /* jeśli nie piszemy do aktualnego, to zapisz do bufora i wyjdź */ if (id && id != window_current->id) { window_write(id, line); /* XXX trzeba jeszcze walnąć odświeżenie prompta */ goto done; } /* jeśli mamy ukrywać wszystko, wychodzimy */ if (pager_lines == -2) goto done; window_write(window_current->id, line); /* ukryj prompt, jeśli jesteśmy w trakcie readline */ if (in_readline) { int i; old_prompt = xstrdup(rl_prompt); rl_end = 0; #ifdef HAVE_RL_SET_PROMPT /* rl_set_prompt(NULL); */ #else /* rl_expand_prompt(NULL); */ #endif rl_redisplay(); printf("\r"); for (i = 0; i < strlen(old_prompt); i++) printf(" "); printf("\r"); } printf("%s", line); if (pager_lines >= 0) { pager_lines++; if (pager_lines >= screen_lines - 2) { const char *prompt = format_find("readline_more"); char *tmp; in_readline++; /* rl_set_prompt(NULL); */ #ifdef HAVE_RL_SET_PROMPT rl_set_prompt((char *) prompt); #else rl_expand_prompt((char *) prompt); #endif pager_lines = -1; tmp = readline((char *) prompt); in_readline--; if (tmp) { xfree(tmp); pager_lines = 0; } else { printf("\n"); pager_lines = -2; } printf("\033[A\033[K"); /* XXX brzydko */ } } /* jeśli jesteśmy w readline, pokaż z powrotem prompt */ if (in_readline) { rl_end = old_end; #ifdef HAVE_RL_SET_PROMPT rl_set_prompt(old_prompt); #else rl_expand_prompt(old_prompt); #endif xfree(old_prompt); rl_forced_update_display(); } done: if (line_buf) xfree(line_buf); /* say it! ;) */ if (config_speech_app) { say_it(s->str); string_free(s, 1); } } /* * ui_readline_beep() * * wydaje dźwięk na konsoli. */ static void ui_readline_beep() { printf("\a"); fflush(stdout); } /* * current_prompt() * * zwraca wskaźnik aktualnego prompta. statyczny bufor, nie zwalniać. */ static const char *current_prompt() { static char buf[80]; const char *prompt = buf; int count = list_count(windows); char *tmp, *act = window_activity(); if (window_current->query_nick) { if (count > 1 || window_current->id != 1) { if (act) { tmp = format_string(format_find("readline_prompt_query_win_act"), window_current->query_nick, itoa(window_current->id), act); xfree(act); } else tmp = format_string(format_find("readline_prompt_query_win"), window_current->query_nick, itoa(window_current->id)); } else tmp = format_string(format_find("readline_prompt_query"), window_current->query_nick, NULL); strlcpy(buf, tmp, sizeof(buf)); xfree(tmp); } else { char *format_win = "readline_prompt_win", *format_nowin = "readline_prompt", *format_win_act = "readline_prompt_win_act"; if (GG_S_B(config_status)) { format_win = "readline_prompt_away_win"; format_nowin = "readline_prompt_away"; format_win_act = "readline_prompt_away_win_act"; } if (GG_S_I(config_status)) { format_win = "readline_prompt_invisible_win"; format_nowin = "readline_prompt_invisible"; format_win_act = "readline_prompt_invisible_win_act"; } if (count > 1 || window_current->id != 1) { if (act) { tmp = format_string(format_find(format_win_act), itoa(window_current->id), act); xfree(act); } else tmp = format_string(format_find(format_win), itoa(window_current->id)); strlcpy(buf, tmp, sizeof(buf)); xfree(tmp); } else strlcpy(buf, format_find(format_nowin), sizeof(buf)); } if (no_prompt) prompt = ""; return prompt; } /* * my_readline() * * malutki wrapper na readline(), który przygotowuje odpowiedniego prompta * w zależności od tego, czy jesteśmy zajęci czy nie i informuje resztę * programu, że jesteśmy w trakcie czytania linii i jeśli chcą wyświetlać, * powinny najpierw sprzątnąć. */ static char *my_readline() { const char *prompt = current_prompt(); char *res, *tmp; in_readline = 1; #ifdef HAVE_RL_SET_PROMPT rl_set_prompt(prompt); #else rl_expand_prompt(prompt); #endif res = readline((char *) prompt); in_readline = 0; tmp = saprintf("%s%s\n", prompt, (res) ? res : ""); window_write(window_current->id, tmp); xfree(tmp); return res; } /* * ui_readline_init() * * inicjalizacja interfejsu readline. */ void ui_readline_init() { char c; struct sigaction sa; window_current = window_add(); window_refresh(); ui_print = ui_readline_print; ui_postinit = ui_readline_postinit; ui_loop = ui_readline_loop; ui_beep = ui_readline_beep; ui_event = ui_readline_event; ui_deinit = ui_readline_deinit; rl_initialize(); rl_getc_function = my_getc; rl_readline_name = "gg"; rl_attempted_completion_function = (CPPFunction *) my_completion; rl_completion_entry_function = (void*) empty_generator; rl_set_key("\033[[A", binding_help, emacs_standard_keymap); rl_set_key("\033OP", binding_help, emacs_standard_keymap); rl_set_key("\033[11~", binding_help, emacs_standard_keymap); rl_set_key("\033[M", binding_help, emacs_standard_keymap); rl_set_key("\033[[B", binding_quick_list, emacs_standard_keymap); rl_set_key("\033OQ", binding_quick_list, emacs_standard_keymap); rl_set_key("\033[12~", binding_quick_list, emacs_standard_keymap); rl_set_key("\033[N", binding_quick_list, emacs_standard_keymap); //rl_set_key("\033[24~", binding_toggle_debug, emacs_standard_keymap); for (c = '0'; c <= '9'; c++) rl_bind_key_in_map(c, bind_handler_window, emacs_meta_keymap); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigint_handler; sigaction(SIGINT, &sa, NULL); sa.sa_handler = sigcont_handler; sigaction(SIGCONT, &sa, NULL); #ifdef SIGWINCH sa.sa_handler = sigwinch_handler; sigaction(SIGWINCH, &sa, NULL); #endif rl_get_screen_size(&screen_lines, &screen_columns); if (screen_lines < 1) screen_lines = 24; if (screen_columns < 1) screen_columns = 80; ui_screen_width = screen_columns; ui_screen_height = screen_lines; ui_need_refresh = 0; } /* * ui_readline_postinit() * * funkcja uruchamiana po wczytaniu konfiguracji. */ static void ui_readline_postinit() { } /* * ui_readline_deinit() * * zamyka to, co związane z interfejsem. */ static void ui_readline_deinit() { window_free(); } /* * ui_readline_loop() * * główna pętla programu. wczytuje dane z klawiatury w międzyczasie * obsługując sieć i takie tam. */ static void ui_readline_loop() { for (;;) { char *line = my_readline(); /* jeśli wciśnięto Ctrl-D i jesteśmy w query, wyjdźmy */ if (!line && window_current->query_nick) { ui_event("command", 0, "query", NULL); continue; } /* jeśli wciśnięto Ctrl-D, to zamknij okienko */ if (!line && list_count(windows) > 1) { window_remove(window_current->id, 0); continue; } if (!line) { if (config_ctrld_quits) break; else { printf("\n"); continue; } } if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') { string_t s = string_init(NULL); line[strlen(line) - 1] = 0; string_append(s, line); xfree(line); no_prompt = 1; rl_bind_key(9, rl_insert); while ((line = my_readline())) { if (!strcmp(line, ".")) { xfree(line); break; } string_append(s, line); string_append(s, "\r\n"); xfree(line); } rl_bind_key(9, rl_complete); no_prompt = 0; if (!line) { printf("\n"); string_free(s, 1); continue; } line = string_free(s, 0); } /* jeśli linia nie jest pusta, dopisz do historii */ if (*line) add_history(line); pager_lines = 0; command_exec(window_current->query_nick, line, 0); pager_lines = -1; xfree(line); } if (!batch_mode && !quit_message_send) { putchar('\n'); print("quit"); putchar('\n'); quit_message_send = 1; } } /* * ui_readline_event() * * obsługa zdarzeń wysyłanych z ekg do interfejsu. */ static int ui_readline_event(const char *event, ...) { va_list ap; int result = 0; va_start(ap, event); if (!strcmp(event, "variable_changed")) { char *name = va_arg(ap, char*); if (!strcasecmp(name, "sort_windows") && config_sort_windows) { list_t l; int id = 1; for (l = windows; l; l = l->next) { struct window *w = l->data; w->id = id++; } } } if (!strcasecmp(event, "command")) { int quiet = va_arg(ap, int); char *command = va_arg(ap, char*); if (!strcasecmp(command, "query-current")) { int *param = va_arg(ap, uin_t*); if (window_current->query_nick) *param = get_uin(window_current->query_nick); else *param = 0; goto cleanup; } if (!strcasecmp(command, "query-nicks")) { char ***param = va_arg(ap, char***); list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->query_nick) continue; else array_add(param, xstrdup(w->query_nick)); } goto cleanup; } if (!strcasecmp(command, "query")) { char *param = va_arg(ap, char*); if (!param && !window_current->query_nick) goto cleanup; if (param) { int id; if ((id = window_find_query(param))) { printq("query_exist", param, itoa(id)); return 1; } printq("query_started", param); xfree(window_current->query_nick); window_current->query_nick = xstrdup(param); } else { if (!quiet) printf("\n"); /* XXX brzydkie */ printq("query_finished", window_current->query_nick); xfree(window_current->query_nick); window_current->query_nick = NULL; } result = 1; } if (!strcasecmp(command, "find")) { char *tmp = NULL; if (window_current->query_nick) { struct userlist *u = userlist_find(0, window_current->query_nick); struct conference *c = conference_find(window_current->query_nick); int uin; if (u && u->uin) tmp = saprintf("find %d", u->uin); if (c && c->name) tmp = saprintf("/conference --find %s", c->name); if (!u && (uin = atoi(window_current->query_nick))) tmp = saprintf("find %d", uin); } if (!tmp) tmp = saprintf("find %d", config_uin); command_exec(NULL, tmp, 0); xfree(tmp); goto cleanup; } if (!strcasecmp(command, "window")) { char *p1 = va_arg(ap, char*), *p2 = va_arg(ap, char*); if (!p1 || !strcasecmp(p1, "list")) { if (!quiet) window_list(); } else if (!strcasecmp(p1, "last")) { if (window_last_id != -1) window_switch(window_last_id, quiet); } else if (!strcasecmp(p1, "active")) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->act) window_switch(w->id, quiet); } } else if (!strcasecmp(p1, "oldest")) { list_t l; int id = 0; time_t id_time = time(NULL); for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->act && w->act_time < id_time) { id = w->id; id_time = w->act_time; } } if (id) window_switch(id, quiet); } else if (!strcasecmp(p1, "new")) { window_add(); } else if (!strcasecmp(p1, "next")) { window_switch(window_current->id + 1, quiet); } else if (!strcasecmp(p1, "prev")) { window_switch(window_current->id - 1, quiet); } else if (!strcasecmp(p1, "kill")) { int id = (p2) ? atoi(p2) : window_current->id; window_remove(id, quiet); } else if (!strcasecmp(p1, "switch")) { if (!p2) { printq("not_enough_params", "window"); } else window_switch(atoi(p2), quiet); } else if (!strcasecmp(p1, "refresh")) { window_refresh(); } else if (!strcasecmp(p1, "clear")) { window_clear(); window_refresh(); } else printq("invalid_params", "window"); result = 1; } if (!strcasecmp(command, "bind")) { char *p1 = va_arg(ap, char*), *p2 = va_arg(ap, char*), *p3 = va_arg(ap, char*); if (p1 && (!strcasecmp(p1, "-a") || !strcasecmp(p1, "--add"))) { if ((!p2 || !p3) && !quiet) print("not_enough_params", "bind"); else bind_sequence(p2, p3, quiet); } else if (p1 && (!strcasecmp(p1, "-d") || !strcasecmp(p1, "--del"))) { if (!p2 && !quiet) print("not_enough_params", "bind"); else bind_sequence(p2, NULL, quiet); } else { if (p1 && (!strcasecmp(p1, "-l") || !strcasecmp(p1, "--list"))) binding_list(quiet, p2, 0); else binding_list(quiet, p1, 0); } result = 1; } } if (!strcasecmp(event, "check_mail")) check_mail(); cleanup: va_end(ap); return result; } /* * window_find() * * szuka struct window dla okna o podanym numerku. * * - id - numer okna. * * struct window dla danego okna. */ static struct window *window_find(int id) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->id == id) return w; } return NULL; } /* * window_add() * * tworzy nowe okno. * * zwraca zaalokowaną struct window. */ static struct window *window_add() { struct window w; int id = 1; /* wyczyść. */ memset(&w, 0, sizeof(w)); /* znajdź pierwszy wolny id okienka. */ while (window_find(id)) id++; w.id = id; /* dopisz, zwróć. */ return list_add(&windows, &w, sizeof(w)); } /* * window_remove() * * usuwa okno o podanym numerze. */ static int window_remove(int id, int quiet) { struct window *w; int i; /* jeśli zostało jedno okienko, nie usuwaj niczego. */ if (list_count(windows) < 2) { printq("window_no_windows"); return -1; } /* jeśli nie ma takiego okienka, idź sobie. */ if (!(w = window_find(id))) { printq("window_noexist"); return -1; } /* jeśli usuwano aktualne okienko, nie kombinuj tylko ustaw 1-sze. */ if (window_current == w) { struct window *newwin = windows->data; /* jeśli usuwane jest pierwszy, weź drugie. */ if (newwin == w) newwin = windows->next->data; window_switch(newwin->id, 0); } /* i sortujemy okienka, w razie potrzeby... */ if (config_sort_windows) { list_t l; int wid = w->id; for (l = windows; l; l = l->next) { struct window *wtmp = l->data; if (wtmp->id > wid) wtmp->id--; } } /* usuń dane zajmowane przez okno. */ for (i = 0; i < MAX_LINES_PER_SCREEN; i++) { xfree(w->line[i]); w->line[i] = NULL; } xfree(w->query_nick); w->query_nick = NULL; list_remove(&windows, w, 1); return 0; } /* * window_switch() * * przełącza do okna o podanym id. */ static int window_switch(int id, int quiet) { struct window *w = window_find(id); if (!w) { printq("window_noexist"); return -1; } if (id != window_current->id) window_last_id = window_current->id; window_current = w; w->act = 0; window_refresh(); #ifdef HAVE_RL_SET_PROMPT rl_set_prompt((char *) current_prompt()); #else rl_expand_prompt((char *) current_prompt()); #endif rl_initialize(); return 0; } /* * window_refresh() * * wyświetla ponownie zawartość okna. * * XXX podpiąć pod Ctrl-L. */ static int window_refresh() { int i; printf("\033[H\033[J"); /* XXX */ for (i = 0; i < MAX_LINES_PER_SCREEN; i++) if (window_current->line[i]) printf("%s", window_current->line[i]); return 0; } /* * window_write() * * dopisuje linię do bufora danego okna. */ static int window_write(int id, const char *line) { struct window *w = window_find(id); int i = 1; if (!line || !w) return -1; /* jeśli cały bufor zajęty, zwolnij pierwszą linię i przesuń do góry */ if (w->line[MAX_LINES_PER_SCREEN - 1]) { xfree(w->line[0]); for (i = 1; i < MAX_LINES_PER_SCREEN; i++) w->line[i - 1] = w->line[i]; w->line[MAX_LINES_PER_SCREEN - 1] = NULL; } /* znajdź pierwszą wolną linię i się wpisz. */ for (i = 0; i < MAX_LINES_PER_SCREEN; i++) if (!w->line[i]) { w->line[i] = xstrdup(line); break; } if (w != window_current) { if (!w->act) { w->act = 1; w->act_time = time(NULL); } #ifdef HAVE_RL_SET_PROMPT rl_set_prompt((char *) current_prompt()); #else rl_expand_prompt((char *) current_prompt()); #endif rl_redisplay(); } return 0; } /* * window_clear() * * czyści zawartość aktualnego okna. */ static void window_clear() { int i; for (i = 0; i < MAX_LINES_PER_SCREEN; i++) { xfree(window_current->line[i]); window_current->line[i] = NULL; } } /* * window_find_query() * * znajduje id okna, w którym prowadzona jest rozmowa z daną osobą. jeśli * nie ma takiego, zwraca zero. */ static int window_find_query(const char *nick) { list_t l; if (!nick) return 0; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->query_nick && !strcasecmp(w->query_nick, nick)) return w->id; } return 0; } /* * window_list() * * wyświetla listę okien. */ static void window_list() { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->query_nick) print("window_list_query", itoa(w->id), w->query_nick); else print("window_list_nothing", itoa(w->id)); } } /* * window_make_query() * * tworzy nowe okno rozmowy w zależności od aktualnych ustawień. */ static int window_make_query(const char *nick) { /* szuka pierwszego wolnego okienka i je zajmuje */ if ((config_make_window & 3) == 1) { list_t l; for (l = windows; l; l = l->next) { struct window *w = l->data; if (!w->query_nick) { w->query_nick = xstrdup(nick); if (w == window_current) { print("query_started", nick); #ifdef HAVE_RL_SET_PROMPT rl_set_prompt((char *) current_prompt()); #else rl_expand_prompt((char *) current_prompt()); #endif } else print("window_id_query_started", itoa(w->id), nick); if (get_uin(nick) && !(ignored_check(get_uin(nick)) & IGNORE_EVENTS)) event_check(EVENT_QUERY, get_uin(nick), nick); return w->id; } } } if ((config_make_window & 3) == 1 || (config_make_window & 3) == 2) { struct window *w; if (!(w = window_add())) return 0; w->query_nick = xstrdup(nick); print("window_id_query_started", itoa(w->id), nick); if (get_uin(nick) && !(ignored_check(get_uin(nick)) & IGNORE_EVENTS)) event_check(EVENT_QUERY, get_uin(nick), nick); return w->id; } return 0; } /* * window_free() * * zwalnia pamięć po wszystkich strukturach okien. */ static void window_free() { list_t l; window_current = NULL; for (l = windows; l; l = l->next) { struct window *w = l->data; int i; xfree(w->query_nick); w->query_nick = NULL; for (i = 0; i < MAX_LINES_PER_SCREEN; i++) { xfree(w->line[i]); w->line[i] = NULL; } } list_destroy(windows, 1); windows = NULL; } /* * window_activity() * * zwraca string z actywnymi oknami */ static char *window_activity() { string_t s = string_init(""); int first = 1; list_t l; char *act = NULL; for (l = windows; l; l = l->next) { struct window *w = l->data; if (w->act) { if (!first) string_append_c(s, ','); string_append(s, itoa(w->id)); first = 0; } } if (!first) act = strdup(s->str); string_free(s, 1); return act; } /* * bind_find_command() * * szuka komendy, którą należy wykonać dla danego klawisza. */ static char *bind_find_command(const char *seq) { list_t l; if (!seq) return NULL; for (l = bindings; l; l = l->next) { struct binding *s = l->data; if (s->key && !strcasecmp(s->key, seq)) return s->action; } return NULL; } /* * bind_handler_ctrl() * * obsługuje klawisze Ctrl-A do Ctrl-Z, wywołując przypisane im akcje. */ static int bind_handler_ctrl(int a, int key) { char *tmp = saprintf("Ctrl-%c", 'A' + key - 1); int foo = pager_lines; if (foo < 0) pager_lines = 0; command_exec(NULL, bind_find_command(tmp), 0); if (foo < 0) pager_lines = foo; xfree(tmp); return 0; } /* * bind_handler_alt() * * obsługuje klawisze z Altem, wywołując przypisane im akcje. */ static int bind_handler_alt(int a, int key) { char *tmp = saprintf("Alt-%c", key); int foo = pager_lines; if (foo < 0) pager_lines = 0; command_exec(NULL, bind_find_command(tmp), 0); if (foo < 0) pager_lines = foo; xfree(tmp); return 0; } /* * bind_handler_window() * * obsługuje klawisze Alt-1 do Alt-0, zmieniając okna na odpowiednie. */ static int bind_handler_window(int a, int key) { if (key > '0' && key <= '9') window_switch(key - '0', 0); else window_switch(10, 0); return 0; } static int bind_sequence(const char *seq, const char *command, int quiet) { char *nice_seq = NULL; if (!seq) return -1; if (command && bind_find_command(seq)) { printq("bind_seq_exist", seq); return -1; } if (!strncasecmp(seq, "Ctrl-", 5) && strlen(seq) == 6 && xisalpha(seq[5])) { int key = CTRL(xtoupper(seq[5])); if (command) { rl_bind_key(key, bind_handler_ctrl); nice_seq = xstrdup(seq); nice_seq[0] = xtoupper(nice_seq[0]); nice_seq[1] = xtolower(nice_seq[1]); nice_seq[2] = xtolower(nice_seq[2]); nice_seq[3] = xtolower(nice_seq[3]); nice_seq[5] = xtoupper(nice_seq[5]); } else rl_unbind_key(key); } else if (!strncasecmp(seq, "Alt-", 4) && strlen(seq) == 5) { if (command) { rl_bind_key_in_map(xtolower(seq[4]), bind_handler_alt, emacs_meta_keymap); nice_seq = xstrdup(seq); nice_seq[0] = xtoupper(nice_seq[0]); nice_seq[1] = xtolower(nice_seq[1]); nice_seq[2] = xtolower(nice_seq[2]); nice_seq[4] = xtoupper(nice_seq[4]); } else rl_unbind_key_in_map(xtolower(seq[4]), emacs_meta_keymap); } else { printq("bind_seq_incorrect", seq); return -1; } if (command) { struct binding s; s.key = nice_seq; s.action = xstrdup(command); s.internal = 0; s.arg = s.default_action = s.default_arg = NULL; list_add(&bindings, &s, sizeof(s)); if (!quiet) { print("bind_seq_add", s.key); config_changed = 1; } } else { list_t l; for (l = bindings; l; l = l->next) { struct binding *s = l->data; if (s->key && !strcasecmp(s->key, seq)) { list_remove(&bindings, s, 1); if (!quiet) { print("bind_seq_remove", seq); config_changed = 1; } return 0; } } } return 1; } ekg-1.9~pre+r2855/src/ui.h000066400000000000000000000036201174410337000151750ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2004 Wojtek Kaniewski * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __UI_H #define __UI_H #include #include "config.h" void (*ui_init)(void); void (*ui_postinit)(void); void (*ui_loop)(void); void (*ui_print)(const char *target, int separate, const char *line); void (*ui_beep)(void); int (*ui_event)(const char *event, ...); void (*ui_deinit)(void); int ui_screen_width; int ui_screen_height; volatile sig_atomic_t ui_need_refresh; extern void ui_none_init(void); extern void ui_batch_init(void); #ifdef WITH_UI_READLINE #define MAX_LINES_PER_SCREEN 50 extern void ui_readline_init(void); #endif #ifdef WITH_UI_NCURSES #ifdef HAVE_NCURSES_H # include #else # ifdef HAVE_NCURSES_NCURSES_H # include # endif #endif WINDOW *header, *status; int window_printat(WINDOW *w, int x, int y, const char *format, void *data_, int fgcolor, int bold, int bgcolor, int status); int config_backlog_overlap; int config_backlog_size; int config_beep_title; extern void ui_ncurses_init(void); extern void header_statusbar_resize(const char *name); #endif #ifdef WITH_UI_GTK extern void ui_gtk_init(void); /* rest in ui-gtk.h */ #endif #endif /* __UI_H */ ekg-1.9~pre+r2855/src/userlist.c000066400000000000000000000577471174410337000164500ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2006 Wojtek Kaniewski * Robert J. Woźny * Piotr Domagalski * Jakub Klama * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "commands.h" #include "dynstuff.h" #include "libgadu.h" #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "userlist.h" #include "vars.h" #include "xmalloc.h" #ifndef PATH_MAX # define PATH_MAX _POSIX_PATH_MAX #endif list_t userlist = NULL; struct ignore_label ignore_labels[IGNORE_LABELS_COUNT + 1] = { { IGNORE_STATUS, "status" }, { IGNORE_STATUS_DESCR, "descr" }, { IGNORE_NOTIFY, "notify" }, { IGNORE_MSG, "msg" }, { IGNORE_DCC, "dcc" }, { IGNORE_EVENTS, "events" }, { IGNORE_SMSAWAY, "smsaway" }, { IGNORE_DISPLAY, "display" }, { 0, NULL } }; /* * userlist_compare() * * funkcja pomocna przy list_add_sorted(). * * - data1, data2 - dwa wpisy userlisty do porównania. * * zwraca wynik strcasecmp() na nazwach userów. */ static int userlist_compare(void *data1, void *data2) { struct userlist *a = data1, *b = data2; if (!a || !a->display || !b || !b->display) return 1; #ifdef HAVE_STRCOLL if (strcoll_usable) return strcoll(a->display, b->display); else #endif return strcasecmp(a->display, b->display); } /* * userlist_read() * * wczytuje listę kontaktów z pliku ~/.gg/userlist w postaci eksportu * tekstowego listy kontaktów windzianego klienta. * * 0/-1 */ int userlist_read() { const char *filename; char *buf; FILE *f; if (!(filename = prepare_path("userlist", 0))) return -1; if (!(f = fopen(filename, "r"))) return -1; while ((buf = read_file(f))) { struct userlist u; char **entry, *uin; char *tmp; int i, count; memset(&u, 0, sizeof(u)); if (buf[0] == '#' || (buf[0] == '/' && buf[1] == '/')) { xfree(buf); continue; } entry = array_make(buf, ";", 9, 0, 0); if ((count = array_count(entry)) < 7) { array_free(entry); continue; } uin = entry[6]; if (!strncasecmp(uin, "gg:", 3)) uin += 3; if ((strcmp(uin, "") && !(u.uin = atoi(uin)))) { array_free(entry); xfree(buf); continue; } for (i = 0; i < count; i++) { if (!strcmp(entry[i], "(null)") || !strcmp(entry[i], "")) { xfree(entry[i]); entry[i] = NULL; } } u.first_name = unescape(entry[0]); u.last_name = unescape(entry[1]); u.nickname = unescape(entry[2]); tmp = unescape(entry[3]); if (entry[3] && !valid_nick(tmp)) { u.display = saprintf("_%s", tmp); xfree(tmp); } else u.display = tmp; u.mobile = unescape(entry[4]); tmp = unescape(entry[5]); u.groups = group_init(tmp); xfree(tmp); u.status = GG_STATUS_NOT_AVAIL; /* mamy adres e-mail? */ if (count > 7) { u.email = unescape(entry[7]); if (count > 8) { tmp = unescape(entry[8]); u.foreign = saprintf(";%s", tmp); xfree(tmp); } } for (i = 0; i < count; i++) xfree(entry[i]); xfree(entry); xfree(buf); list_add_sorted(&userlist, &u, sizeof(u), userlist_compare); } fclose(f); return 0; } /* * userlist_set() * * ustawia listę kontaktów na podaną. * * 0/-1 */ int userlist_set(const char *contacts, int config) { string_t vars = NULL; char *buf, *cont, *contsave; if (!contacts) return -1; userlist_clear(); if (config) vars = string_init(NULL); contsave = cont = xstrdup(contacts); while ((buf = get_line(&cont))) { struct userlist u; char **entry, *uin; int i, count; char *tmp; memset(&u, 0, sizeof(u)); if (buf[0] == '#' || (buf[0] == '/' && buf[1] == '/')) continue; if (!strncmp(buf, "__config", 8)) { char **entry; if (!config) continue; entry = array_make(buf, ";", 7, 0, 0); for (i = 1; i < 6; i++) string_append(vars, entry[i]); array_free(entry); continue; } entry = array_make(buf, ";", 8, 0, 0); if ((count = array_count(entry)) < 7) { array_free(entry); continue; } uin = entry[6]; if (!strncasecmp(uin, "gg:", 3)) uin += 3; if ((strcmp(uin, "") && !(u.uin = atoi(uin)))) { array_free(entry); continue; } for (i = 0; i < count; i++) { if (!strcmp(entry[i], "(null)") || !strcmp(entry[i], "")) { xfree(entry[i]); entry[i] = NULL; } } u.first_name = unescape(entry[0]); u.last_name = unescape(entry[1]); u.nickname = unescape(entry[2]); u.display = unescape(entry[3]); if (u.display && !valid_nick(u.display)) { tmp = u.display; u.display = saprintf("_%s", tmp); free(tmp); } u.mobile = unescape(entry[4]); tmp = unescape(entry[5]); u.groups = group_init(tmp); free(tmp); u.status = GG_STATUS_NOT_AVAIL; /* mamy adres e-mail? */ if (count > 7) { u.email = unescape(entry[7]); if (count > 8) { tmp = unescape(entry[8]); u.foreign = saprintf(";%s", tmp); free(tmp); } } array_free(entry); list_add_sorted(&userlist, &u, sizeof(u), userlist_compare); } xfree(contsave); if (config) { char *tmp = string_free(vars, 0); gg_debug(GG_DEBUG_MISC, "// received ekg variables digest: %s\n", tmp); if (variable_undigest(tmp)) { xfree(tmp); return -1; } if (sess && sess->state == GG_STATE_CONNECTED) { if (config_reason) { iso_to_cp((unsigned char *) config_reason); gg_change_status_descr(sess, config_status, config_reason); cp_to_iso((unsigned char *) config_reason); } else gg_change_status(sess, config_status); } xfree(tmp); } return 0; } /* * userlist_dump() * * zapisuje listę kontaktów w postaci tekstowej. * * zwraca zaalokowany bufor, który należy zwolnić. */ char *userlist_dump() { string_t s = string_init(NULL); list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; char *groups, *line; char *strings[8]; size_t i; static const char escstr[] = "\r\n;"; groups = group_to_string(u->groups, 1, 0); strings[0] = escape(u->first_name, escstr); strings[1] = escape(u->last_name, escstr); strings[2] = escape(u->nickname, escstr); strings[3] = escape(u->display, escstr); strings[4] = escape(u->mobile, escstr); strings[5] = escape(groups, escstr); xfree(groups); strings[6] = escape(u->email, escstr); strings[7] = escape(u->foreign, escstr); line = saprintf("%s;%s;%s;%s;%s;%s;%s;%s%s\r\n", (u->first_name) ? strings[0] : "", (u->last_name) ? strings[1] : "", (u->nickname) ? strings[2] : "", (u->display) ? strings[3] : "", (u->mobile) ? strings[4] : "", strings[5], (u->uin) ? itoa(u->uin) : "", (u->email) ? strings[6] : "", (u->foreign) ? strings[7] : ""); for (i = sizeof(strings) / sizeof(*strings); i > 0; i--) xfree(strings[i - 1]); string_append(s, line); xfree(line); } return string_free(s, 0); } /* * userlist_write() * * zapisuje listę kontaktów w pliku ~/.gg/userlist (pid == 0) * lub ~/.gg/userlist.pid (pid == 1) */ int userlist_write(int pid) { const char *filename; char *contacts, tmp[PATH_MAX + 1], *pattern; FILE *f; if (!(contacts = userlist_dump())) return -1; if (pid) { pattern = xmalloc(32); snprintf(pattern, 32, "userlist.%d", (int) getpid()); } else pattern = "userlist"; if (!(filename = prepare_path(pattern, 1))) { if (pid) xfree(pattern); xfree(contacts); return -1; } if (pid) { xfree(pattern); snprintf(tmp, sizeof(tmp), "%s.%ld", filename, (long) time(NULL)); } else snprintf(tmp, sizeof(tmp), "%s.%d.%ld", filename, (int) getpid(), (long) time(NULL)); if (!(f = fopen(tmp, "w"))) { xfree(contacts); return -2; } fchmod(fileno(f), config_files_mode_config); fputs(contacts, f); xfree(contacts); if (fclose(f) == EOF) { unlink(tmp); return -2; } if (rename(tmp, filename) == -1) return -2; return 0; } #ifdef WITH_WAP /* * userlist_write_wap() * * zapisuje listę kontaktów w pliku ~/.gg/wapstatus */ int userlist_write_wap() { const char *filename; list_t l; FILE *f; if (!(filename = prepare_path("wapstatus", 1))) return -1; if (!(f = fopen(filename, "w"))) return -1; fchmod(fileno(f), config_files_mode_config); fprintf(f, "%s\n", (sess) ? "C" : "D"); for (l = userlist; l; l = l->next) { struct userlist *u = l->data; char *strings[2]; static const char escstr[] = "\r\n:"; strings[0] = escape(u->display, escstr); strings[1] = escape(u->descr, escstr); fprintf(f, "%s:%d%s%s\n", strings[0], u->status, (u->descr) ? ":" : "", strings[1]); xfree(strings[1]); xfree(strings[0]); } fclose(f); return 0; } #endif /* * userlist_write_crash() * * zapisuje listę kontaktów w sytuacji kryzysowej jak najmniejszym * nakładem pamięci i pracy. */ void userlist_write_crash() { list_t l; char name[32]; FILE *f; chdir(config_dir); snprintf(name, sizeof(name), "userlist.%d", (int) getpid()); if (!(f = fopen(name, "w"))) return; chmod(name, 0400); for (l = userlist; l; l = l->next) { struct userlist *u = l->data; list_t m; fprintf(f, "%s;%s;%s;%s;%s;", (u->first_name) ? u->first_name : "", (u->last_name) ? u->last_name : "", (u->nickname) ? u->nickname : ((u->display) ? u->display: ""), (u->display) ? u->display: "", (u->mobile) ? u->mobile : ""); for (m = u->groups; m; m = m->next) { struct group *g = m->data; if (m != u->groups) fprintf(f, ","); fprintf(f, "%s", g->name); } fprintf(f, ";%s;%s%s\r\n", (u->uin) ? itoa(u->uin) : "", (u->email) ? u->email : "", (u->foreign) ? u->foreign : ""); } fclose(f); } /* * userlist_clear_status() * * czyści stan użytkowników na liście. jeśli uin != 0 to * to czyści danego użytkownika. * * - uin. */ void userlist_clear_status(uin_t uin) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!uin || uin == u->uin) { u->status = GG_STATUS_NOT_AVAIL; memset(&u->ip, 0, sizeof(struct in_addr)); memset(&u->last_ip, 0, sizeof(struct in_addr)); u->port = 0; u->last_port = 0; xfree(u->descr); xfree(u->last_descr); u->descr = NULL; u->last_descr = NULL; } } } /* * userlist_clear() * * czyści listę użytkowników. */ void userlist_clear() { while (userlist) userlist_remove(userlist->data, 1); } /* * userlist_add() * * dodaje użytkownika do listy. * * - uin, * - display. */ struct userlist *userlist_add(uin_t uin, const char *display) { struct userlist u; memset(&u, 0, sizeof(u)); u.uin = uin; u.status = GG_STATUS_NOT_AVAIL; u.display = xstrdup(display); return list_add_sorted(&userlist, &u, sizeof(u), userlist_compare); } /* * userlist_remove() * * usuwa danego użytkownika z listy kontaktów. * * - u * - full - pełne usuwanie? w przeciwnym wypadku zostawi użytkowników * ignorowanych i blokowanych, */ int userlist_remove(struct userlist *u, int full) { int metagroups = 0; list_t l; if (!u) return -1; for (l = u->groups; l; l = l->next) { struct group *g = l->data; if (!strncmp(g->name, "__", 2)) metagroups = 1; } if (!full && (group_member(u, "__blocked") || ignored_check(u->uin))) { xfree(u->first_name); u->first_name = NULL; xfree(u->last_name); u->last_name = NULL; xfree(u->nickname); u->nickname = NULL; xfree(u->display); u->display = NULL; xfree(u->mobile); u->mobile = NULL; xfree(u->descr); u->descr = NULL; xfree(u->foreign); u->foreign = NULL; xfree(u->last_descr); u->last_descr = NULL; xfree(u->email); u->email = NULL; for (l = u->groups; l; ) { struct group *g = l->data; l = l->next; if (strncmp(g->name, "__", 2)) { xfree(g->name); list_remove(&u->groups, g, 1); } } return 0; } xfree(u->first_name); xfree(u->last_name); xfree(u->nickname); xfree(u->display); xfree(u->mobile); xfree(u->descr); xfree(u->foreign); xfree(u->last_descr); xfree(u->email); for (l = u->groups; l; l = l->next) { struct group *g = l->data; xfree(g->name); } list_destroy(u->groups, 1); list_remove(&userlist, u, 1); return 0; } /* * userlist_replace() * * usuwa i dodaje na nowo użytkownika, żeby został umieszczony na odpowiednim * (pod względem kolejności alfabetycznej) miejscu. głupie to trochę, ale * przy listach jednokierunkowych nie za bardzo chce mi się mieszać z * przesuwaniem elementów listy. * * - u. * * zwraca zero jeśli jest ok, -1 jeśli błąd. */ int userlist_replace(struct userlist *u) { if (!u) return -1; if (list_remove(&userlist, u, 0)) return -1; if (!list_add_sorted(&userlist, u, 0, userlist_compare)) return -1; return 0; } /* * userlist_find() * * znajduje odpowiednią strukturę `userlist' odpowiadającą danemu numerkowi * lub jego opisowi. * * - uin, * - display. */ struct userlist *userlist_find(uin_t uin, const char *display) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (uin && u->uin == uin) return u; if (display && u->display && !strcasecmp(u->display, display)) return u; } return NULL; } /* * userlist_find_mobile() * * znajduje użytkownika, do którego należy podany numer telefonu. * * - mobile. */ struct userlist *userlist_find_mobile(const char *mobile) { list_t l; for (l = userlist; l; l = l->next) { struct userlist *u = l->data; if (mobile && u->mobile && !strcasecmp(u->mobile, mobile)) return u; } return NULL; } /* * userlist_type() * * zwraca rodzaj użytkownika dla funkcji gg_*_notify_ex(). * * - u - wpis użytkownika * * GG_USER_* */ char userlist_type(struct userlist *u) { char res = GG_USER_NORMAL; if (!u) return res; if (group_member(u, "__offline")) res = GG_USER_OFFLINE; if (group_member(u, "__blocked")) res = GG_USER_BLOCKED; return res; } /* * str_to_uin() * * funkcja, która zajmuje się zamianą stringa na * liczbę i sprawdzeniem, czy to prawidłowy uin. * * zwraca uin lub 0 w przypadku błędu. */ uin_t str_to_uin(const char *text) { char *tmp; long num; if (!text) return 0; errno = 0; num = strtol(text, &tmp, 0); if (*text == '\0' || *tmp != '\0') return 0; if ((errno == ERANGE || (num == LONG_MAX || num == LONG_MIN)) || num > UINT_MAX || num < 0) return 0; return (uin_t) num; } /* * valid_nick() * * sprawdza, czy nick nie zawiera znaków specjalnych, * które mogłyby powodować problemy. * * zwraca 1 jeśli nick jest w porządku, w przeciwnym razie 0. */ int valid_nick(const char *nick) { int i; const char *wrong[] = { "(null)", "__debug", "__status", "__current", "__contacts", "*", "$", NULL }; if (!nick) return 0; for (i = 0; wrong[i]; i++) { if (!strcasecmp(nick, wrong[i])) return 0; } if (nick[0] == '@' || nick[0] == '#') return 0; return 1; } /* * get_uin() * * jeśli podany tekst jest liczbą (ale nie jednocześnie nazwą użytkownika), * zwraca jej wartość. jeśli jest nazwą użytkownika w naszej liście kontaktów, * zwraca jego numerek. jeśli tekstem jestem znak ,,$'', pyta ui o aktualnego * rozmówcę i zwraca jego uin. inaczej zwraca zero. * * - text. */ uin_t get_uin(const char *text) { uin_t uin = str_to_uin(text); struct userlist *u = userlist_find(uin, text); if (u) return u->uin; if (text && !strcmp(text, "$")) ui_event("command", 0, "query-current", &uin, NULL); return uin; } /* * format_user() * * zwraca ładny (ew. kolorowy) tekst opisujący dany numerek. jeśli jest * w naszej liście kontaktów, formatuje używając `known_user', w przeciwnym * wypadku używa `unknown_user'. wynik jest w statycznym buforze. * * - uin - numerek danej osoby. */ const char *format_user(uin_t uin) { struct userlist *u = userlist_find(uin, NULL); static char buf[100], *tmp; if (!u || !u->display) { if (uin == config_uin && config_nick && *config_nick) tmp = format_string(format_find("known_user"), config_nick, itoa(uin)); else tmp = format_string(format_find("unknown_user"), itoa(uin)); } else tmp = format_string(format_find("known_user"), u->display, itoa(uin)); strlcpy(buf, tmp, sizeof(buf)); xfree(tmp); return buf; } /* * ignored_remove() * * usuwa z listy ignorowanych numerków. * * - uin. */ int ignored_remove(uin_t uin) { struct userlist *u = userlist_find(uin, NULL); list_t l; int level; if (!u) return -1; if (!(level = ignored_check(uin))) return -1; for (l = u->groups; l; ) { struct group *g = l->data; l = l->next; if (strncasecmp(g->name, "__ignored", 9)) continue; xfree(g->name); list_remove(&u->groups, g, 1); } if (!u->display && !u->groups) { userlist_remove(u, 1); return 0; } if (sess && (level & IGNORE_STATUS || level & IGNORE_STATUS_DESCR)) { gg_remove_notify_ex(sess, u->uin, userlist_type(u)); gg_add_notify_ex(sess, u->uin, userlist_type(u)); } return 0; } /* * ignored_add() * * dopisuje do listy ignorowanych numerków. * * - uin. * - level. */ int ignored_add(uin_t uin, int level) { struct userlist *u; char *tmp; if (ignored_check(uin)) return -1; if (!(u = userlist_find(uin, NULL))) u = userlist_add(uin, NULL); tmp = saprintf("__ignored_%d", level); group_add(u, tmp); xfree(tmp); if (level & IGNORE_STATUS) u->status = GG_STATUS_NOT_AVAIL; if (level & IGNORE_STATUS_DESCR) u->status = ekg_hide_descr_status(u->status); return 0; } /* * ignored_check() * * czy dany numerek znajduje się na liście ignorowanych. * * - uin. */ int ignored_check(uin_t uin) { struct userlist *u = userlist_find(uin, NULL); list_t l; if (!u) return 0; for (l = u->groups; l; l = l->next) { struct group *g = l->data; if (!strcasecmp(g->name, "__ignored")) return IGNORE_ALL; if (!strncasecmp(g->name, "__ignored_", 10)) return atoi(g->name + 10); } return 0; } /* * ignore_flags() * * zamienia łańcuch znaków na odpowiedni * poziom ignorowania w postaci liczby. */ int ignore_flags(const char *str) { int x, y, ret = 0; char **arr; if (!str) return ret; arr = array_make(str, "|,:", 0, 1, 0); for (x = 0; arr[x]; x++) { if (!strcmp(arr[x], "*")) { ret = IGNORE_ALL; break; } for (y = 0; ignore_labels[y].name; y++) if (!strcasecmp(arr[x], ignore_labels[y].name)) ret |= ignore_labels[y].level; } array_free(arr); return ret; } /* * ignore_format() * * zwraca statyczny łańcuch znaków reprezentujący * dany poziom ignorowania. */ const char *ignore_format(int level) { static char buf[200]; int i, comma = 0; buf[0] = 0; if (level == IGNORE_ALL) return "*"; for (i = 0; ignore_labels[i].name; i++) { if (level & ignore_labels[i].level) { if (comma++) strlcat(buf, ",", sizeof(buf)); strlcat(buf, ignore_labels[i].name, sizeof(buf)); } } return buf; } /* * blocked_remove() * * usuwa z listy blokowanych numerków. * * - uin. */ int blocked_remove(uin_t uin) { struct userlist *u = userlist_find(uin, NULL); list_t l; if (!u) return -1; if (!group_member(u, "__blocked")) return -1; gg_remove_notify_ex(sess, u->uin, userlist_type(u)); for (l = u->groups; l; ) { struct group *g = l->data; l = l->next; if (strcasecmp(g->name, "__blocked")) continue; xfree(g->name); list_remove(&u->groups, g, 1); } if (!u->display && !u->groups) userlist_remove(u, 1); else gg_add_notify_ex(sess, u->uin, userlist_type(u)); return 0; } /* * blocked_add() * * dopisuje do listy blokowanych numerków. * * - uin. */ int blocked_add(uin_t uin) { struct userlist *u = userlist_find(uin, NULL); if (u && group_member(u, "__blocked")) return -1; if (!u) u = userlist_add(uin, NULL); else gg_remove_notify_ex(sess, uin, userlist_type(u)); group_add(u, "__blocked"); gg_add_notify_ex(sess, uin, userlist_type(u)); return 0; } /* * userlist_send() * * wysyła do serwera userlistę, wywołując gg_notify_ex() */ void userlist_send() { list_t l; uin_t *uins; char *types; int i, count; for (count = 0, l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!u->display && userlist_type(u) == GG_USER_NORMAL) continue; count++; } uins = xmalloc(count * sizeof(uin_t)); types = xmalloc(count * sizeof(char)); for (i = 0, l = userlist; l; l = l->next) { struct userlist *u = l->data; if (!u->display && userlist_type(u) == GG_USER_NORMAL) continue; uins[i] = u->uin; types[i] = userlist_type(u); i++; } gg_notify_ex(sess, uins, types, count); xfree(uins); xfree(types); } /* * group_compare() * * funkcja pomocna przy list_add_sorted(). * * - data1, data2 - dwa wpisy grup do porównania. * * zwraca wynik strcasecmp() na nazwach grup. */ static int group_compare(void *data1, void *data2) { struct group *a = data1, *b = data2; if (!a || !a->name || !b || !b->name) return 0; return strcasecmp(a->name, b->name); } /* * group_add() * * dodaje użytkownika do podanej grupy. * * - u - wpis usera, * - group - nazwa grupy. */ int group_add(struct userlist *u, const char *group) { struct group g; list_t l; if (!u || !group) return -1; for (l = u->groups; l; l = l->next) { struct group *g = l->data; if (!strcasecmp(g->name, group)) return -1; } g.name = xstrdup(group); list_add_sorted(&u->groups, &g, sizeof(g), group_compare); return 0; } /* * group_remove() * * usuwa użytkownika z podanej grupy. * * - u - wpis usera, * - group - nazwa grupy. * * zwraca 0 jeśli się udało, inaczej -1. */ int group_remove(struct userlist *u, const char *group) { list_t l; if (!u || !group) return -1; for (l = u->groups; l; l = l->next) { struct group *g = l->data; if (!strcasecmp(g->name, group)) { xfree(g->name); list_remove(&u->groups, g, 1); return 0; } } return -1; } /* * group_member() * * sprawdza czy użytkownik jest członkiem danej grupy. * * zwraca 1 jeśli tak, 0 jeśli nie. */ int group_member(struct userlist *u, const char *group) { list_t l; if (!u || !group) return 0; for (l = u->groups; l; l = l->next) { struct group *g = l->data; if (!strcasecmp(g->name, group)) return 1; } return 0; } /* * group_init() * * inicjuje listę grup użytkownika na podstawie danego ciągu znaków, * w którym kolejne nazwy grup są rozdzielone przecinkiem. * * - names - nazwy grup. * * zwraca listę `struct group' jeśli się udało, inaczej NULL. */ list_t group_init(const char *names) { list_t l = NULL; char **groups; int i; if (!names) return NULL; groups = array_make(names, ",", 0, 1, 0); for (i = 0; groups[i]; i++) { struct group g; g.name = xstrdup(groups[i]); list_add_sorted(&l, &g, sizeof(g), group_compare); } array_free(groups); return l; } /* * group_to_string() * * zmienia listę grup na ciąg znaków rodzielony przecinkami. * * - groups - lista grup. * - meta - czy dołączyć ,,meta-grupy''? * - sep - czy oddzielać przecinkiem _i_ spacją? * * zwraca zaalokowany ciąg znaków lub NULL w przypadku błędu. */ char *group_to_string(list_t groups, int meta, int sep) { string_t foo = string_init(NULL); list_t l; int comma = 0; for (l = groups; l; l = l->next) { struct group *g = l->data; if (!meta && !strncmp(g->name, "__", 2)) { comma = 0; continue; } if (comma) string_append(foo, (sep) ? ", " : ","); comma = 1; string_append(foo, g->name); } return string_free(foo, 0); } ekg-1.9~pre+r2855/src/userlist.h000066400000000000000000000070601174410337000164340ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USERLIST_H #define __USERLIST_H #include "config.h" #include #include #include #include #include #include "libgadu.h" #include "dynstuff.h" #include "stuff.h" struct userlist { char *first_name; /* imię */ char *last_name; /* nazwisko */ char *nickname; /* pseudonim */ char *display; /* wyświetlania nazwa */ char *mobile; /* komórka */ char *email; /* adres e-mail */ list_t groups; /* grupy, do których należy */ uin_t uin; /* numer */ int status; /* aktualny stan */ char *descr; /* opis/powód stanu */ struct in_addr ip; /* adres ip */ unsigned short port; /* port */ int protocol; /* wersja protokołu */ char *foreign; /* dla kompatybilności */ time_t last_seen; /* jesli jest niedostepny/ukryty, to od kiedy */ char *last_descr; /* j.w. ostatni opis */ struct in_addr last_ip; /* j.w. ostatni adres ip */ unsigned short last_port; /* j.w. ostatni port */ int image_size; /* maksymalny rozmiar obrazków */ }; struct group { char *name; }; enum ignore_t { IGNORE_STATUS = TOGGLE_BIT(1), IGNORE_STATUS_DESCR = TOGGLE_BIT(2), IGNORE_MSG = TOGGLE_BIT(3), IGNORE_DCC = TOGGLE_BIT(4), IGNORE_EVENTS = TOGGLE_BIT(5), IGNORE_NOTIFY = TOGGLE_BIT(6), IGNORE_SMSAWAY = TOGGLE_BIT(7), IGNORE_DISPLAY = TOGGLE_BIT(8), IGNORE_ALL = 255 }; struct ignore_label { int level; char *name; }; #define IGNORE_LABELS_COUNT 8 struct ignore_label ignore_labels[IGNORE_LABELS_COUNT + 1]; list_t userlist; int userlist_read(void); int userlist_write(int pid); #ifdef WITH_WAP int userlist_write_wap(void); #endif void userlist_write_crash(void); void userlist_clear_status(uin_t uin); struct userlist *userlist_add(uin_t uin, const char *display); int userlist_remove(struct userlist *u, int full); int userlist_replace(struct userlist *u); void userlist_send(void); struct userlist *userlist_find(uin_t uin, const char *display); struct userlist *userlist_find_mobile(const char *mobile); char *userlist_dump(void); void userlist_clear(void); #define userlist_free userlist_clear int userlist_set(const char *contacts, int config); char userlist_type(struct userlist *u); int ignored_add(uin_t uin, int level); int ignored_remove(uin_t uin); int ignored_check(uin_t uin); int ignore_flags(const char *str); const char *ignore_format(int level); int blocked_add(uin_t uin); int blocked_remove(uin_t uin); int group_add(struct userlist *u, const char *group); int group_remove(struct userlist *u, const char *group); int group_member(struct userlist *u, const char *group); char *group_to_string(list_t l, int meta, int sep); list_t group_init(const char *groups); uin_t str_to_uin(const char *text); int valid_nick(const char *nick); uin_t get_uin(const char *text); const char *format_user(uin_t uin); #endif /* __USERLIST_H */ ekg-1.9~pre+r2855/src/vars.c000066400000000000000000000734301174410337000155340ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2005 Wojtek Kaniewski * Robert J. Woźny * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include "dynstuff.h" #include "libgadu.h" #include "mail.h" #ifndef HAVE_STRLCAT # include "../compat/strlcat.h" #endif #ifndef HAVE_STRLCPY # include "../compat/strlcpy.h" #endif #include "stuff.h" #include "themes.h" #include "ui.h" #include "vars.h" #include "xmalloc.h" list_t variables = NULL; /* * dd_*() * * funkcje informujące, czy dana grupa zmiennych ma zostać wyświetlona. * równie dobrze można było przekazać wskaźnik do zmiennej, która musi * być różna od zera, ale dzięki funkcjom nie trzeba będzie mieszać w * przyszłości. */ static int dd_beep(const char *name) { return (config_beep); } static int dd_check_mail(const char *name) { return (config_check_mail); } static int dd_dcc(const char *name) { return (config_dcc); } static int dd_sound(const char *name) { return (config_sound_app != NULL); } static int dd_sms(const char *name) { return (config_sms_app != NULL); } static int dd_log(const char *name) { return (config_log); } static int dd_color(const char *name) { return (config_display_color); } #ifdef WITH_UI_NCURSES static int dd_contacts(const char *name) { return (config_contacts); } #endif /* * variable_init() * * inicjuje listę zmiennych. */ void variable_init() { variable_add("uin", "ui", VAR_INT, 1, &config_uin, changed_uin, NULL, NULL); variable_add("password", "pa", VAR_STR, 0, &config_password, NULL, NULL, NULL); variable_add("email", "em", VAR_STR, 1, &config_email, NULL, NULL, NULL); #ifdef HAVE_VOIP variable_add("audio_device", "ad", VAR_STR, 1, &config_audio_device, NULL, NULL, NULL); #else variable_add("audio_device", "ad", VAR_STR, 2, NULL, NULL, NULL, NULL); #endif variable_add("auto_away", "aa", VAR_INT, 1, &config_auto_away, NULL, NULL, NULL); variable_add("auto_away_keep_descr", "ak", VAR_BOOL, 1, &config_auto_away_keep_descr, NULL, NULL, NULL); variable_add("auto_back", "ab", VAR_INT, 1, &config_auto_back, NULL, NULL, NULL); variable_add("auto_conference", "aC", VAR_BOOL, 1, &config_auto_conference, NULL, NULL, NULL); variable_add("auto_find", "af", VAR_BOOL, 1, &config_auto_find, NULL, NULL, NULL); variable_add("auto_reconnect", "ac", VAR_INT, 1, &config_auto_reconnect, NULL, NULL, NULL); variable_add("auto_save", "as", VAR_INT, 1, &config_auto_save, changed_auto_save, NULL, NULL); #ifdef WITH_ASPELL variable_add("aspell", "al", VAR_BOOL, 1, &config_aspell, changed_aspell, NULL, NULL); variable_add("aspell_lang", "ag", VAR_STR, 1, &config_aspell_lang, changed_aspell, NULL, NULL); variable_add("aspell_encoding", "an", VAR_STR, 1, &config_aspell_encoding, changed_aspell, NULL, NULL); #else variable_add("aspell", "al", VAR_BOOL, 2, NULL, NULL, NULL, NULL); variable_add("aspell_lang", "ag", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("aspell_encoding", "an", VAR_STR, 2, NULL, NULL, NULL, NULL); #endif variable_add("away_reason", "ar", VAR_STR, 1, &config_away_reason, changed_xxx_reason, NULL, NULL); variable_add("back_reason", "br", VAR_STR, 1, &config_back_reason, changed_xxx_reason, NULL, NULL); variable_add("ffc_reason", "fr", VAR_STR, 1, &config_ffc_reason, changed_xxx_reason, NULL, NULL); variable_add("dnd_reason", "dR", VAR_STR, 1, &config_dnd_reason, changed_xxx_reason, NULL, NULL); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) { variable_add("backlog_overlap", "bo", VAR_INT, 1, &config_backlog_overlap, NULL, NULL, NULL); variable_add("backlog_size", "bs", VAR_INT, 1, &config_backlog_size, changed_backlog_size, NULL, NULL); } else { variable_add("backlog_overlap", "bo", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("backlog_size", "bs", VAR_INT, 2, NULL, NULL, NULL, NULL); } #else variable_add("backlog_overlap", "bo", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("backlog_size", "bs", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif variable_add("beep", "be", VAR_BOOL, 1, &config_beep, NULL, NULL, NULL); variable_add("beep_msg", "bm", VAR_BOOL, 1, &config_beep_msg, NULL, NULL, dd_beep); variable_add("beep_chat", "bc", VAR_BOOL, 1, &config_beep_chat, NULL, NULL, dd_beep); variable_add("beep_notify", "bn", VAR_BOOL, 1, &config_beep_notify, NULL, NULL, dd_beep); variable_add("beep_mail", "bM", VAR_BOOL, 1, &config_beep_mail, NULL, NULL, dd_beep); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) variable_add("beep_title", "bt", VAR_INT, 1, &config_beep_title, NULL, NULL, NULL); else variable_add("beep_title", "bt", VAR_INT, 2, NULL, NULL, NULL, NULL); #else variable_add("beep_title", "bt", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif variable_add("check_mail", "cm", VAR_MAP, 1, &config_check_mail, changed_check_mail, variable_map(4, 0, 0, "no", 1, 2, "mbox", 2, 1, "maildir", 4, 0, "notify"), NULL); variable_add("check_mail_frequency", "cf", VAR_INT, 1, &config_check_mail_frequency, changed_check_mail, NULL, dd_check_mail); variable_add("check_mail_folders", "cF", VAR_STR, 1, &config_check_mail_folders, changed_check_mail_folders, NULL, dd_check_mail); variable_add("completion_notify", "cn", VAR_MAP, 1, &config_completion_notify, NULL, variable_map(5, 0, 0, "none", 1, 2, "add", 2, 1, "addremove", 4, 0, "busy", 8, 0, "invisible"), NULL); #ifdef WITH_UI_READLINE if (ui_init == ui_readline_init) variable_add("ctrld_quits", "cq", VAR_BOOL, 1, &config_ctrld_quits, NULL, NULL, NULL); else variable_add("ctrld_quits", "cq", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #else variable_add("ctrld_quits", "cq", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif #if defined WITH_UI_NCURSES || defined WITH_UI_GTK if ( #ifdef WITH_UI_NCURSES ui_init == ui_ncurses_init #endif #if defined WITH_UI_NCURSES && defined WITH_UI_GTK || #endif #ifdef WITH_UI_GTK ui_init == ui_gtk_init #endif ) { variable_add("contacts", "co", VAR_INT, 1, &config_contacts, NULL, NULL, NULL); variable_add("contacts_groups", "cg", VAR_STR, 1, &config_contacts_groups, NULL, NULL, dd_contacts); variable_add("contacts_options", "cO", VAR_STR, 1, &config_contacts_options, NULL, NULL, dd_contacts); variable_add("contacts_size", "cs", VAR_INT, 1, &config_contacts_size, NULL, NULL, dd_contacts); } else { variable_add("contacts", "co", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("contacts_groups", "cg", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("contacts_options", "cO", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("contacts_size", "cs", VAR_INT, 2, NULL, NULL, NULL, NULL); } #else variable_add("contacts", "co", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("contacts_groups", "cg", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("contacts_options", "cO", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("contacts_size", "cs", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif variable_add("dcc", "dc", VAR_BOOL, 1, &config_dcc, changed_dcc, NULL, NULL); variable_add("dcc_ip", "di", VAR_STR, 1, &config_dcc_ip, changed_dcc, NULL, dd_dcc); variable_add("dcc_dir", "dd", VAR_STR, 1, &config_dcc_dir, NULL, NULL, dd_dcc); variable_add("dcc_backups", "db", VAR_BOOL, 1, &config_dcc_backups, NULL, NULL, dd_dcc); variable_add("dcc_filter", "df", VAR_BOOL, 1, &config_dcc_filter, NULL, NULL, dd_dcc); variable_add("dcc_limit", "dl", VAR_STR, 1, &config_dcc_limit, NULL, NULL, dd_dcc); variable_add("dcc_port", "dP", VAR_INT, 1, &config_dcc_port, changed_dcc, NULL, dd_dcc); variable_add("display_ack", "da", VAR_INT, 1, &config_display_ack, NULL, variable_map(4, 0, 0, "none", 1, 0, "all", 2, 0, "delivered", 3, 0, "queued"), NULL); variable_add("display_color", "dC", VAR_INT, 1, &config_display_color, NULL, NULL, NULL); variable_add("display_color_map", "dm", VAR_STR, 1, &config_display_color_map, NULL, NULL, dd_color); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) { variable_add("display_crap", "dr", VAR_BOOL, 1, &config_display_crap, NULL, NULL, NULL); variable_add("display_daychanges", "dD", VAR_BOOL, 1, &config_display_daychanges, NULL, NULL, NULL); } else { variable_add("display_crap", "dr", VAR_BOOL, 2, NULL, NULL, NULL, NULL); variable_add("display_daychanges", "dD", VAR_BOOL, 2, NULL, NULL, NULL, NULL); } #else variable_add("display_crap", "dr", VAR_BOOL, 2, NULL, NULL, NULL, NULL); variable_add("display_daychanges", "dD", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif variable_add("display_notify", "dn", VAR_MAP, 1, &config_display_notify, NULL, variable_map(4, 0, 0, "none", 1, 2, "all", 2, 1, "significant", 4, 0, "unknown"), NULL); variable_add("display_pl_chars", "dp", VAR_BOOL, 1, &config_display_pl_chars, NULL, NULL, NULL); variable_add("display_sent", "ds", VAR_BOOL, 1, &config_display_sent, NULL, NULL, NULL); #if defined HAVE_LIBJPEG || defined HAVE_LIBUNGIF variable_add("display_token", "dT", VAR_BOOL, 1, &config_display_token, NULL, NULL, NULL); #else variable_add("display_token", "dT", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif variable_add("display_welcome", "dw", VAR_BOOL, 1, &config_display_welcome, NULL, NULL, NULL); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) variable_add("display_transparent", "dt", VAR_BOOL, 1, &config_display_transparent, NULL, NULL, NULL); else variable_add("display_transparent", "dt", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #else variable_add("display_transparent", "dt", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif variable_add("emoticons", "eM", VAR_BOOL, 1, &config_emoticons, NULL, NULL, NULL); #ifdef HAVE_OPENSSL variable_add("encryption", "en", VAR_INT, 1, &config_encryption, NULL, variable_map(4, 0, 0, "no", 1, 0, "yes", 2, 0, "recv", 3, 0, "send"), NULL); #else variable_add("encryption", "en", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) variable_add("enter_scrolls", "es", VAR_BOOL, 1, &config_enter_scrolls, NULL, NULL, NULL); else variable_add("enter_scrolls", "es", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #else variable_add("enter_scrolls", "es", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif variable_add("events_delay", "ev", VAR_INT, 1, &config_events_delay, NULL, NULL, NULL); variable_add("files_mode_config", "Mc", VAR_INT, 1, &config_files_mode_config_int, changed_files_mode, NULL, NULL); variable_add("files_mode_received", "Mr", VAR_INT, 1, &config_files_mode_received_int, changed_files_mode, NULL, NULL); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) variable_add("header_size", "hs", VAR_INT, 1, &config_header_size, header_statusbar_resize, NULL, NULL); else variable_add("header_size", "hs", VAR_INT, 2, NULL, NULL, NULL, NULL); #else variable_add("header_size", "hs", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif variable_add("ignore_unknown_sender", "iu", VAR_BOOL, 1, &config_ignore_unknown_sender, NULL, NULL, NULL); variable_add("ignore_empty_msg", "im", VAR_BOOL, 1, &config_ignore_empty_msg, NULL, NULL, NULL); variable_add("image_size", "iS", VAR_INT, 1, &config_image_size, NULL, NULL, NULL); variable_add("keep_reason", "kr", VAR_INT, 1, &config_keep_reason, NULL, NULL, NULL); variable_add("last", "la", VAR_MAP, 1, &config_last, NULL, variable_map(4, 0, 0, "none", 1, 2, "all", 2, 1, "separate", 4, 0, "sent"), NULL); variable_add("last_size", "ls", VAR_INT, 1, &config_last_size, NULL, NULL, NULL); variable_add("local_ip", "ld", VAR_STR, 1, &config_local_ip, changed_local_ip, NULL, NULL); variable_add("log", "lo", VAR_MAP, 1, &config_log, NULL, variable_map(4, 0, 0, "none", 1, 2, "file", 2, 1, "dir", 4, 0, "gzip"), NULL); variable_add("log_ignored", "li", VAR_INT, 1, &config_log_ignored, NULL, NULL, dd_log); variable_add("log_status", "lS", VAR_INT, 1, &config_log_status, NULL, variable_map(3, 0, 0, "no", 1, 2, "yes", 2, 1, "descr"), dd_log); variable_add("log_path", "lp", VAR_STR, 1, &config_log_path, NULL, NULL, dd_log); variable_add("log_timestamp", "lt", VAR_STR, 1, &config_log_timestamp, NULL, NULL, dd_log); variable_add("make_window", "mw", VAR_MAP, 1, &config_make_window, NULL, variable_map(4, 0, 0, "none", 1, 2, "usefree", 2, 1, "always", 4, 0, "nomsg"), NULL); variable_add("msg_as_chat", "mc", VAR_INT, 1, &config_msg_as_chat, NULL, variable_map(3, 0, 0, "no", 1, 2, "sendonly", 2, 1, "yes"), NULL); variable_add("mesg", "ma", VAR_INT, 1, &config_mesg, changed_mesg, variable_map(3, 0, 0, "no", 1, 2, "yes", 2, 1, "default"), NULL); #ifdef WITH_UI_NCURSES variable_add("mouse", "mo", VAR_BOOL, 1, &config_mouse, NULL, NULL, NULL); #else variable_add("mouse", "mo", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif variable_add("nick", "ni", VAR_STR, 1, &config_nick, NULL, NULL, NULL); variable_add("proxy", "pr", VAR_STR, 1, &config_proxy, changed_proxy, NULL, NULL); variable_add("proxy_forwarding", "pf", VAR_STR, 1, &config_proxy_forwarding, NULL, NULL, NULL); variable_add("random_reason", "rr", VAR_MAP, 1, &config_random_reason, NULL, variable_map(5, 0, 0, "none", 1, 0, "away", 2, 0, "notavail", 4, 0, "avail", 8, 0, "invisible"), NULL); variable_add("reason_limit", "rl", VAR_BOOL, 1, &config_reason_limit, NULL, NULL, NULL); variable_add("receive_images", "ra", VAR_BOOL, 1, &config_receive_images, NULL, NULL, NULL); #ifdef HAVE_REGEX_H variable_add("regex_flags", "rf", VAR_MAP, 1, &config_regex_flags, NULL, variable_map(3, 0, 0, "none", 1, 0, "basic", 2, 0, "case"), NULL); #else variable_add("regex_flags", "rf", VAR_MAP, 2, NULL, NULL, NULL, NULL); #endif variable_add("quit_reason", "qr", VAR_STR, 1, &config_quit_reason, changed_xxx_reason, NULL, NULL); variable_add("query_commands", "qc", VAR_BOOL, 1, &config_query_commands, NULL, NULL, NULL); variable_add("save_password", "sp", VAR_BOOL, 1, &config_save_password, NULL, NULL, NULL); variable_add("save_question", "sq", VAR_BOOL, 1, &config_save_question, NULL, NULL, NULL); variable_add("server", "se", VAR_STR, 1, &config_server, NULL, NULL, NULL); variable_add("server_save", "ss", VAR_BOOL, 1, &config_server_save, NULL, NULL, NULL); variable_add("irssi_set_mode", "is", VAR_BOOL, 1, &config_irssi_set_mode, NULL, NULL, NULL); variable_add("slash_messages", "sM", VAR_BOOL, 1, &config_slash_messages, NULL, NULL, NULL); variable_add("sms_away", "sa", VAR_MAP, 1, &config_sms_away, NULL, variable_map(4, 0, 0, "none", 1, 2, "all", 2, 1, "separate", 4, 0, "invisible"), dd_sms); variable_add("sms_away_limit", "sl", VAR_INT, 1, &config_sms_away_limit, NULL, NULL, dd_sms); variable_add("sms_max_length", "sm", VAR_INT, 1, &config_sms_max_length, NULL, NULL, dd_sms); variable_add("sms_number", "sn", VAR_STR, 1, &config_sms_number, NULL, NULL, dd_sms); variable_add("sms_send_app", "sA", VAR_STR, 1, &config_sms_app, NULL, NULL, NULL); variable_add("sort_windows", "sw", VAR_BOOL, 1, &config_sort_windows, NULL, NULL, NULL); variable_add("sound_msg_file", "Sm", VAR_STR, 1, &config_sound_msg_file, NULL, NULL, dd_sound); variable_add("sound_chat_file", "Sc", VAR_STR, 1, &config_sound_chat_file, NULL, NULL, dd_sound); variable_add("sound_sysmsg_file", "Ss", VAR_STR, 1, &config_sound_sysmsg_file, NULL, NULL, dd_sound); variable_add("sound_notify_file", "Sn", VAR_STR, 1, &config_sound_notify_file, NULL, NULL, dd_sound); variable_add("sound_mail_file", "SM", VAR_STR, 1, &config_sound_mail_file, NULL, NULL, dd_sound); variable_add("sound_app", "Sa", VAR_STR, 1, &config_sound_app, NULL, NULL, NULL); variable_add("speech_app", "SA", VAR_STR, 1, &config_speech_app, NULL, NULL, NULL); variable_add("status_window", "Sw", VAR_INT, 1, &config_status_window, NULL, variable_map(3, 0, 0, "query", 1, 2, "current", 2, 1, "status"), NULL); #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) { variable_add("statusbar_size", "sS", VAR_INT, 1, &config_statusbar_size, header_statusbar_resize, NULL, NULL); variable_add("statusbar_fgcolor", "sF", VAR_INT, 1, &config_statusbar_fgcolor, NULL, NULL, NULL); variable_add("statusbar_bgcolor", "sB", VAR_INT, 1, &config_statusbar_bgcolor, NULL, NULL, NULL); } else { variable_add("statusbar_size", "sS", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("statusbar_fgcolor", "sF", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("statusbar_bgcolor", "sB", VAR_INT, 2, NULL, NULL, NULL, NULL); } #else variable_add("statusbar_size", "sS", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("statusbar_fgcolor", "sF", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("statusbar_bgcolor", "sB", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif variable_add("tab_command", "tc", VAR_STR, 1, &config_tab_command, NULL, NULL, NULL); variable_add("theme", "th", VAR_STR, 1, &config_theme, changed_theme, NULL, NULL); variable_add("time_deviation", "td", VAR_INT, 1, &config_time_deviation, NULL, NULL, NULL); variable_add("timestamp", "ts", VAR_STR, 1, &config_timestamp, NULL, NULL, NULL); variable_add("userlist_backup", "ub", VAR_BOOL, 1, &config_userlist_backup, NULL, NULL, NULL); #ifdef WITH_WAP variable_add("wap_enabled", "we", VAR_INT, 1, &config_wap_enabled, NULL, NULL, NULL); #else variable_add("wap_enabled", "we", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif #ifdef WITH_UI_NCURSES if (ui_init == ui_ncurses_init) { variable_add("windows_save", "ws", VAR_MAP, 1, &config_windows_save, NULL, variable_map(3, 0, 0, "no", 1, 0, "quit", 2, 0, "save"), NULL); variable_add("windows_layout", "wl", VAR_STR, 2, &config_windows_layout, NULL, NULL, NULL); variable_add("datestamp", "dS", VAR_STR, 1, &config_datestamp, NULL, NULL, NULL); } else { variable_add("windows_save", "ws", VAR_MAP, 2, NULL, NULL, NULL, NULL); variable_add("windows_layout", "wl", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("datestamp", "dS", VAR_STR, 2, NULL, NULL, NULL, NULL); } #else variable_add("windows_save", "ws", VAR_MAP, 2, NULL, NULL, NULL, NULL); variable_add("windows_layout", "wl", VAR_STR, 2, NULL, NULL, NULL, NULL); variable_add("datestamp", "dS", VAR_STR, 2, NULL, NULL, NULL, NULL); #endif variable_add("status", "st", VAR_INT, 2, &config_status, NULL, NULL, NULL); variable_add("protocol", "pR", VAR_INT, 2, &config_protocol, NULL, NULL, NULL); variable_add("reason", "re", VAR_STR, 2, &config_reason, NULL, NULL, NULL); variable_add("interface", "in", VAR_STR, 2, &config_interface, NULL, NULL, NULL); variable_add("password_cp1250", "c1", VAR_BOOL, 2, &config_password_cp1250, NULL, NULL, NULL); variable_add("last_sysmsg", "LS", VAR_INT, 2, &config_last_sysmsg, NULL, NULL, NULL); #ifdef WITH_IOCTLD variable_add("ioctld_enable", "Ie", VAR_INT, 1, &config_ioctld_enable, NULL, NULL, NULL); variable_add("ioctld_net_port", "Ip", VAR_INT, 1, &config_ioctld_net_port, NULL, NULL, NULL); #else variable_add("ioctld_enable", "Ie", VAR_INT, 2, NULL, NULL, NULL, NULL); variable_add("ioctld_net_port", "Ip", VAR_INT, 2, NULL, NULL, NULL, NULL); #endif } /* * variable_set_default() * * ustawia pewne standardowe wartości zmiennych * nieliczbowych. */ void variable_set_default() { xfree(config_timestamp); xfree(config_display_color_map); xfree(config_dcc_limit); config_timestamp = xstrdup("%H:%M "); config_display_color_map = xstrdup("nTgGbBrR"); config_dcc_limit = xstrdup("30/30"); #ifdef WITH_ASPELL xfree(config_aspell_lang); xfree(config_aspell_encoding); config_aspell_lang = xstrdup("pl"); config_aspell_encoding = xstrdup("iso8859-2"); #endif } /* * variable_find() * * znajduje strukturę `variable' opisującą zmienną o podanej nazwie. * * - name. */ struct variable *variable_find(const char *name) { list_t l; int hash; if (!name) return NULL; hash = ekg_hash(name); for (l = variables; l; l = l->next) { struct variable *v = l->data; if (!v->ptr) continue; if (v->name_hash == hash && !strcasecmp(v->name, name)) return v; } return NULL; } /* * variable_map() * * tworzy nową mapę wartości. jeśli któraś z wartości powinna wyłączyć inne * (na przykład w ,,log'' 1 wyłącza 2, 2 wyłącza 1, ale nie mają wpływu na 4) * należy dodać do ,,konflikt''. * * - count - ilość, * - ... - wartość, konflikt, opis. * * zaalokowana tablica. */ struct value_map *variable_map(int count, ...) { struct value_map *res; va_list ap; int i; res = xcalloc(count + 1, sizeof(struct value_map)); va_start(ap, count); for (i = 0; i < count; i++) { res[i].value = va_arg(ap, int); res[i].conflicts = va_arg(ap, int); res[i].label = xstrdup(va_arg(ap, char*)); } va_end(ap); return res; } /* * variable_add() * * dodaje zmienną do listy zmiennych. * * - name - nazwa, * - short_name - krótka nazwa, * - type - typ zmiennej, * - display - czy i jak ma wyświetlać, * - ptr - wskaźnik do zmiennej, * - notify - funkcja powiadomienia, * - map - mapa wartości, * - dyndisplay - funkcja sprawdzająca czy wyświetlić zmienną. * * zwraca 0 jeśli się udało, jeśli nie to -1. */ int variable_add(const char *name, const char *short_name, int type, int display, void *ptr, void (*notify)(const char*), struct value_map *map, int (*dyndisplay)(const char *name)) { struct variable v; list_t l; if (!name || (type != VAR_FOREIGN && !short_name)) return -1; if (type != VAR_FOREIGN) { for (l = variables; l; l = l->next) { struct variable *v = l->data; if (!strcmp(v->short_name, short_name)) { fprintf(stderr, "Error! Variable short name conflict:\n- short name: \"%s\"\n- existing variable: \"%s\"\n- conflicting variable: \"%s\"\n\nPress any key to continue...", short_name, v->name, name); getchar(); } } } memset(&v, 0, sizeof(v)); v.name = xstrdup(name); v.name_hash = ekg_hash(name); v.type = type; if (short_name) strlcpy(v.short_name, short_name, sizeof(v.short_name)); v.display = display; v.ptr = ptr; v.notify = notify; v.map = map; v.dyndisplay = dyndisplay; return (list_add(&variables, &v, sizeof(v)) ? 0 : -1); } /* * variable_set() * * ustawia wartość podanej zmiennej. jeśli to zmienna liczbowa lub boolowska, * zmienia ciąg na liczbę. w przypadku boolowskich, rozumie zwroty typu `on', * `off', `yes', `no' itp. jeśli dana zmienna jest bitmapą, akceptuje wartość * w postaci listy flag oraz konstrukcje `+flaga' i `-flaga'. * * - name - nazwa zmiennej, * - value - nowa wartość, * - allow_foreign - czy ma pozwalać dopisywać obce zmienne. */ int variable_set(const char *name, const char *value, int allow_foreign) { struct variable *v = variable_find(name); if (!v && allow_foreign) { variable_add(name, "##", VAR_FOREIGN, 2, xstrdup(value), NULL, NULL, NULL); return -1; } if (!v && !allow_foreign) return -1; switch (v->type) { case VAR_INT: case VAR_MAP: { const char *p = value; int hex, tmp; if (!value) return -2; if (v->map && v->type == VAR_INT && !xisdigit(*p)) { int i; for (i = 0; v->map[i].label; i++) if (!strcasecmp(v->map[i].label, value)) value = itoa(v->map[i].value); } if (v->map && v->type == VAR_MAP && !xisdigit(*p)) { int i, k = *(int*)(v->ptr); int mode = 0; /* 0 set, 1 add, 2 remove */ char **args; if (*p == '+') { mode = 1; p++; } else if (*p == '-') { mode = 2; p++; } if (!mode) k = 0; args = array_make(p, ",", 0, 1, 0); for (i = 0; args[i]; i++) { int j, found = 0; for (j = 0; v->map[j].label; j++) { if (!strcasecmp(args[i], v->map[j].label)) { found = 1; if (mode == 2) k &= ~(v->map[j].value); if (mode == 1) k &= ~(v->map[j].conflicts); if (mode == 1 || !mode) k |= v->map[j].value; } } if (!found) { array_free(args); return -2; } } array_free(args); value = itoa(k); } p = value; if ((hex = !strncasecmp(p, "0x", 2))) p += 2; while (*p && *p != ' ') { if (hex && !xisxdigit(*p)) return -2; if (!hex && !xisdigit(*p)) return -2; p++; } tmp = strtol(value, NULL, 0); if (v->map) { int i; for (i = 0; v->map[i].label; i++) { if ((tmp & v->map[i].value) && (tmp & v->map[i].conflicts)) return -2; } } *(int*)(v->ptr) = tmp; if (v->notify) (v->notify)(v->name); if (ui_event) ui_event("variable_changed", v->name); return 0; } case VAR_BOOL: { int tmp; if (!value) return -2; if ((tmp = on_off(value)) == -1) return -2; *(int*)(v->ptr) = tmp; if (v->notify) (v->notify)(v->name); if (ui_event) ui_event("variable_changed", v->name); return 0; } case VAR_STR: { char **tmp = (char**)(v->ptr); xfree(*tmp); if (value) { if (*value == 1) *tmp = base64_decode(value + 1); else *tmp = xstrdup(value); } else *tmp = NULL; if (v->notify) (v->notify)(v->name); if (ui_event) ui_event("variable_changed", v->name); return 0; } } return -1; } /* * variable_free() * * zwalnia pamięć używaną przez zmienne. */ void variable_free() { list_t l; for (l = variables; l; l = l->next) { struct variable *v = l->data; xfree(v->name); if (v->type == VAR_STR && v->ptr) { xfree(*((char**) v->ptr)); *((char**) v->ptr) = NULL; } if (v->type == VAR_FOREIGN) xfree((char*) v->ptr); if (v->map) { int i; for (i = 0; v->map[i].label; i++) xfree(v->map[i].label); xfree(v->map); } } list_destroy(variables, 1); variables = NULL; } /* * variable_digest() * * tworzy skróconą wersję listy zmiennej do zachowania w liście kontaktów * na serwerze. */ char *variable_digest() { string_t s = string_init(NULL); list_t l; for (l = variables; l; l = l->next) { struct variable *v = l->data; if (!v->ptr) continue; if ((v->type == VAR_INT || v->type == VAR_BOOL || v->type == VAR_MAP) && strcmp(v->name, "uin")) { string_append(s, v->short_name); string_append(s, itoa(*(int*)(v->ptr))); } } for (l = variables; l; l = l->next) { struct variable *v = l->data; char *val; if (!v->ptr) continue; if (!v->type == VAR_STR || !strcmp(v->name, "password") || !strcmp(v->name, "local_ip")) continue; val = *((char**)v->ptr); string_append(s, v->short_name); if (!val) { string_append_c(s, '-'); continue; } if (strchr(val, ':') || val[0] == '+') { char *tmp = base64_encode(val); string_append_c(s, '+'); string_append(s, tmp); string_append_c(s, ':'); xfree(tmp); } else { string_append(s, val); string_append_c(s, ':'); } } return string_free(s, 0); } /* * variable_undigest() * * rozszyfrowuje skrót zmiennych z listy kontaktów i ustawia wszystko, * co trzeba. * * - digest - ciąg znaków. * * 0/-1 */ int variable_undigest(const char *digest) { const char *p = digest; if (!digest) return -1; while (*p) { struct variable *v; list_t l; for (v = NULL, l = variables; l; l = l->next) { struct variable *w = l->data; if (!strncmp(p, w->short_name, 2)) { v = w; break; } } if (!v) { gg_debug(GG_DEBUG_MISC, "// unknown short \"%c%c\"\n", p[0], p[1]); return -1; } p += 2; if (v->type == VAR_INT || v->type == VAR_BOOL || v->type == VAR_MAP) { char *end; int val; val = strtol(p, &end, 10); variable_set(v->name, itoa(val), 0); p = end; } if (v->type == VAR_STR) { char *val = NULL; if (*p == '-') { val = NULL; p++; } else { const char *q; char *tmp; int len = 0, base64 = 0; if (*p == '+') { base64 = 1; p++; } for (q = p; *q && *q != ':'; q++, len++) ; tmp = xstrmid(p, 0, len); gg_debug(GG_DEBUG_MISC, "// got string variable \"%s\"\n", tmp); if (base64) { val = base64_decode(tmp); xfree(tmp); } else val = tmp; p += len + 1; } gg_debug(GG_DEBUG_MISC, "// setting variable %s = \"%s\"\n", v->name, ((val) ? val : "(null)")); variable_set(v->name, val, 0); xfree(val); } } return 0; } /* * variable_help() * * wyświetla pomoc dotyczącą danej zmiennej na podstawie pliku * ${datadir}/ekg/vars.txt. * * - name - nazwa zmiennej. */ void variable_help(const char *name) { FILE *f = fopen(DATADIR "/vars.txt", "r"); char *line, *type = NULL, *def = NULL, *tmp; string_t s = string_init(NULL); int found = 0; if (!f) { print("help_set_file_not_found"); return; } while ((line = read_file(f))) { if (strlen(line) >= 2 && line[0] == '/' && line[1] == '/') { xfree(line); continue; } if (!strcasecmp(line, name)) { found = 1; xfree(line); break; } xfree(line); } if (!found) { fclose(f); print("help_set_var_not_found", name); return; } line = read_file(f); if ((tmp = strstr(line, ": "))) type = xstrdup(tmp + 2); else type = xstrdup("?"); xfree(line); tmp = NULL; line = read_file(f); if ((tmp = strstr(line, ": "))) def = xstrdup(tmp + 2); else def = xstrdup("?"); xfree(line); print("help_set_header", name, type, def); xfree(type); xfree(def); if (tmp) /* jeśli nie jest to ukryta zmienna... */ xfree(read_file(f)); /* ... pomijamy linię */ while ((line = read_file(f))) { if (line[0] != '\t') { xfree(line); break; } if (!strncmp(line, "\t- ", 3) && strcmp(s->str, "")) { print("help_set_body", s->str); string_clear(s); } string_append(s, line + 1); if (line[strlen(line) - 1] != ' ') string_append_c(s, ' '); xfree(line); } if (strcmp(s->str, "")) print("help_set_body", s->str); string_free(s, 1); if (strcmp(format_find("help_set_footer"), "")) print("help_set_footer", name); fclose(f); } ekg-1.9~pre+r2855/src/vars.h000066400000000000000000000042401174410337000155320ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __VARS_H #define __VARS_H #include "dynstuff.h" enum variable_type { VAR_STR, /* ciąg znaków */ VAR_INT, /* liczba całkowita */ VAR_BOOL, /* 0/1, tak/nie, yes/no, on/off */ VAR_FOREIGN, /* nieznana zmienna */ VAR_MAP /* bitmapa */ }; struct value_map { int value; /* wartość */ int conflicts; /* wartości, z którymi koliduje */ char *label; /* nazwa wartości */ }; struct variable { char *name; /* nazwa zmiennej */ char short_name[3]; /* krótka nazwa zmiennej */ int name_hash; /* hash nazwy zmiennej */ int type; /* rodzaj */ int display; /* 0 bez wartości, 1 pokazuje, 2 w ogóle */ void *ptr; /* wskaźnik do zmiennej */ void (*notify)(const char*); /* funkcja wywoływana przy zmianie */ struct value_map *map; /* mapa wartości i etykiet */ int (*dyndisplay)(const char*); /* funkcja sprawdzająca, czy wyświetlić zmienną na liście */ }; list_t variables; void variable_init(void); void variable_set_default(void); struct variable *variable_find(const char *name); struct value_map *variable_map(int count, ...); int variable_add(const char *name, const char *short_name, int type, int display, void *ptr, void (*notify)(const char *name), struct value_map *map, int (*dyndisplay)(const char *name)); int variable_set(const char *name, const char *value, int allow_foreign); char *variable_digest(void); int variable_undigest(const char *digest); void variable_help(const char *name); void variable_free(void); #endif /* __VARS_H */ ekg-1.9~pre+r2855/src/vekg000077500000000000000000000003751174410337000152750ustar00rootroot00000000000000#!/bin/sh # skrypt uruchamiający ekg pod kontrolą valgrinda. przydatny tylko # developerom. w snapshotach go nie ma. valgrind --tool=memcheck --num-callers=10 --trace-children=no --leak-check=yes --show-reachable=yes -v --log-fd=3 ./ekg "$@" 3> ekg.log ekg-1.9~pre+r2855/src/version.h000066400000000000000000000014651174410337000162520ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __VERSION_H #define __VERSION_H #define VERSION "1.9-PRE" #endif /* __VERSION_H */ ekg-1.9~pre+r2855/src/voice.c000066400000000000000000000113761174410337000156670ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002-2006 Wojtek Kaniewski * Adam Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include "libgadu.h" #include "voice.h" #include "stuff.h" #include "xmalloc.h" int voice_fd = -1; gsm voice_gsm_enc = NULL, voice_gsm_dec = NULL; /* * voice_open() * * otwiera urządzenie dźwiękowe, inicjalizuje koder gsm, dopisuje do * list przeglądanych deskryptorów. * * 0/-1. */ int voice_open() { const char *pathname = "/dev/dsp"; struct gg_session s; gsm_signal tmp; int value; if (voice_fd != -1) return -1; if (config_audio_device) { pathname = config_audio_device; if (pathname[0] == '-') pathname++; } if ((voice_fd = open(pathname, O_RDWR)) == -1) goto fail; value = 8000; if (ioctl(voice_fd, SNDCTL_DSP_SPEED, &value) == -1) goto fail; value = 16; if (ioctl(voice_fd, SNDCTL_DSP_SAMPLESIZE, &value) == -1) goto fail; value = 1; if (ioctl(voice_fd, SNDCTL_DSP_CHANNELS, &value) == -1) goto fail; value = AFMT_S16_LE; if (ioctl(voice_fd, SNDCTL_DSP_SETFMT, &value) == -1) goto fail; if (read(voice_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) goto fail; if (!(voice_gsm_dec = gsm_create()) || !(voice_gsm_enc = gsm_create())) goto fail; value = 1; gsm_option(voice_gsm_dec, GSM_OPT_FAST, &value); gsm_option(voice_gsm_dec, GSM_OPT_WAV49, &value); gsm_option(voice_gsm_dec, GSM_OPT_VERBOSE, &value); gsm_option(voice_gsm_dec, GSM_OPT_LTP_CUT, &value); gsm_option(voice_gsm_enc, GSM_OPT_FAST, &value); gsm_option(voice_gsm_enc, GSM_OPT_WAV49, &value); s.fd = voice_fd; s.check = GG_CHECK_READ; s.state = GG_STATE_READING_DATA; s.type = GG_SESSION_USER2; s.id = 0; s.timeout = -1; list_add(&watches, &s, sizeof(s)); return 0; fail: voice_close(); return -1; } /* * voice_close() * * zamyka urządzenie audio i koder gsm. * * brak. */ void voice_close() { list_t l; for (l = watches; l; l = l->next) { struct gg_session *s = l->data; if (s->type == GG_SESSION_USER2) { list_remove(&watches, s, 1); break; } } if (voice_fd != -1) { close(voice_fd); voice_fd = -1; } if (voice_gsm_dec) { gsm_destroy(voice_gsm_dec); voice_gsm_dec = NULL; } if (voice_gsm_enc) { gsm_destroy(voice_gsm_enc); voice_gsm_enc = NULL; } } /* * voice_play() * * odtwarza próbki gsm. * * - buf - bufor z danymi, * - length - długość bufora, * - null - jeśli 1, dekoduje, ale nie odtwarza, * * 0/-1. */ int voice_play(const char *buf, int length, int null) { gsm_signal output[160]; const char *pos = buf; if (length <= 0) return 0; /* XXX głupi łorkaraund do rozmów głosowych GG 5.0.5 */ if (length == GG_DCC_VOICE_FRAME_LENGTH_505 && *buf == 0) { pos++; buf++; length--; } while (pos <= (buf + length - 65)) { if (gsm_decode(voice_gsm_dec, (unsigned char *) pos, output)) return -1; if (!null && write(voice_fd, output, 320) != 320) return -1; pos += 33; if (gsm_decode(voice_gsm_dec, (unsigned char *) pos, output)) return -1; if (!null && write(voice_fd, output, 320) != 320) return -1; pos += 32; } return 0; } /* * voice_record() * * nagrywa próbki gsm. * * - buf - bufor z danymi, * - length - długość bufora, * - null - jeśli 1, nie koduje, * * 0/-1. */ int voice_record(char *buf, int length, int null) { gsm_signal input[160]; const char *pos = buf; /* XXX głupi łorkaraund do rozmów głosowych GG 5.0.5 */ if (length == GG_DCC_VOICE_FRAME_LENGTH_505) { *buf = 0; pos++; buf++; length--; } while (pos <= (buf + length - 65)) { if (read(voice_fd, input, 320) != 320) return -1; if (!null) gsm_encode(voice_gsm_enc, input, (unsigned char *) pos); pos += 32; if (read(voice_fd, input, 320) != 320) return -1; if (!null) gsm_encode(voice_gsm_enc, input, (unsigned char *) pos); pos += 33; } return 0; } /* * Local variables: * c-indentation-style: k&r * c-basic-offset: 8 * indent-tabs-mode: notnil * End: * * vim: shiftwidth=8: */ ekg-1.9~pre+r2855/src/voice.h000066400000000000000000000016671174410337000156760ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __VOICE_H #define __VOICE_H int voice_fd; int voice_open(void); void voice_close(void); int voice_play(const char *buf, int length, int null); int voice_record(char *buf, int length, int null); #endif /* __VOICE_H */ ekg-1.9~pre+r2855/src/xmalloc.c000066400000000000000000000043561174410337000162210ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include "configfile.h" #include "stuff.h" #include "userlist.h" #include "libgadu.h" void ekg_oom_handler() { if (old_stderr) dup2(old_stderr, 2); fprintf(stderr, "\r\n" "\r\n" "*** Brak pamięci ***\r\n" "\r\n" "Próbuję zapisać ustawienia do pliku %s/config.%d i listę kontaktów\r\n" "do pliku %s/userlist.%d, ale nie obiecuję, że cokolwiek z tego\r\n" "wyjdzie.\r\n" "\r\n" "Do pliku %s/debug.%d zapiszę ostatanie komunikaty\r\n" "z okna debugowania.\r\n" "\r\n", config_dir, (int) getpid(), config_dir, (int) getpid(), config_dir, (int) getpid()); config_write_crash(); userlist_write_crash(); debug_write_crash(); exit(1); } void *xcalloc(size_t nmemb, size_t size) { void *tmp = calloc(nmemb, size); if (!tmp) ekg_oom_handler(); return tmp; } void *xmalloc(size_t size) { void *tmp = malloc(size); if (!tmp) ekg_oom_handler(); /* na wszelki wypadek wyczyść bufor */ memset(tmp, 0, size); return tmp; } void xfree(void *ptr) { if (ptr) free(ptr); } void *xrealloc(void *ptr, size_t size) { void *tmp = realloc(ptr, size); if (!tmp) ekg_oom_handler(); return tmp; } char *xstrdup(const char *s) { char *tmp; if (!s) return NULL; if (!(tmp = strdup(s))) ekg_oom_handler(); return tmp; } char *saprintf(const char *format, ...) { va_list ap; char *res; va_start(ap, format); res = gg_vsaprintf(format, ap); va_end(ap); if (!res) ekg_oom_handler(); return res; } ekg-1.9~pre+r2855/src/xmalloc.h000066400000000000000000000023371174410337000162230ustar00rootroot00000000000000/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __XMALLOC_H #define __XMALLOC_H #include #define xnew(t) (xcalloc(1, sizeof(t))) #define xnew_t(t) (xcalloc(1, sizeof(*t))) void ekg_oom_handler(void); void *xcalloc(size_t nmemb, size_t size); void *xmalloc(size_t size); void xfree(void *ptr); void *xrealloc(void *ptr, size_t size); char *xstrdup(const char *s); #ifdef __GNUC__ char *saprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); #else char *saprintf(const char *format, ...); #endif #endif /* __XMALLOC_H */ ekg-1.9~pre+r2855/themes/000077500000000000000000000000001174410337000151045ustar00rootroot00000000000000ekg-1.9~pre+r2855/themes/arim.theme000066400000000000000000000261371174410337000170710ustar00rootroot00000000000000# Based on EKG theme by (sic!) -> sic@hybrid.art.pl # EKG theme by Arim. # Last modified: 10/09/2002 11:52 ack_delivered %) %K ack/%1 (%#)%n\n ack_queued %) %K ack/%1 (%#) -queued-%n\n aliases_add %> %WDodano alias %Y%1%n\n aliases_append %> %WDodano do aliasu %Y%1%n\n aliases_del %> %WAlias %Y%1 %Wzostał usunięty%n\n aliases_exist %! %RAlias %W%1%n %Rjuż istnieje%n\n aliases_invalid %! %RNiewłaściwy parametr%n %C(help alias?)%n\n aliases_list %> %W%[8]1%n %K->%n %g%2%n\n aliases_list_empty %> %WBrak aliasów%n\n aliases_list_next %> %[8]3 %K=>%n %g%2%n\n aliases_noexist %! %RAlias %W%1%n %Rnie istnieje!%n\n already_connected %! %RJuż jesteś połączony!%n\n already_searching %> %RPrzeszukiwanie w toku%n %WWpisz:%n %yfind -stop%n %Waby przerwać...%n\n auto_away %c%#%n %> %CPo%n %W%1%n %Crobię sobie przerwę%n\n auto_away_descr %c%#%n %> %CPo%n %W%1%n %Crobię sobie przerwę: %2%n\n autosaved %> %WNastąpił autozapis ustawień.\n away %c%#%n %> %cWracam za chwilę ... %n\n away_descr %c%#%n %> %cWracam za chwilę: %1%n\n back %c%#%n %> %gJestem z powrotem %n\n back_descr %c%#%n %> %gJestem z powrotem: %1%n\n change %> %WZmieniłeś informacje w katalogu publicznym.%n\n change_failed %! %RBłąd podczas zmiany informacji w katalogu publicznym!%n\n change_not_enough_params %! %RPolecenie wymaga podania %Wwszystkich%n %Rparametrów!%n\n change_timeout %! %RPrzekroczono limit czasu operacji zmiany katalogu publicznego!%n\n conn_broken %! %c%#%n %W---/%n%r*%n%W/---%n %RPołączenie z serwerem przerwane%n\n conn_failed %! %BBłąd podczas łączenia:%n %W%1%n\n conn_stopped %! %BŁączenie przerwane!%n\n conn_timeout %! %BSerwer nie odpowiada. Spróbuj jeszcze raz.%n\n connected %c%#%n %> [%G OK %n] %W<-%n %GPołączono z serwerem%n\n connecting %> %WTrwa łączenie z serwerem...%n\n contacts_header_group %W %1%n contacts_avail %G%1%n contacts_avail_descr %Ki%G%1%n contacts_avail_descr_full %Ki%G%1%n %2 contacts_busy %C%1%n contacts_busy_descr %Ki%C%1%n contacts_busy_descr_full %Ki%C%1%n %2 contacts_not_avail %K%1%n contacts_not_avail_descr %Ki%1%n contacts_not_avail_descr_full %Ki%1%n %2 contacts_invisible %M%1%n contacts_invisible_descr %Ki%M%1%n contacts_invisible_descr_full %Ki%M%1%n %2 contacts_blocking %r%1%n disconn_warning %! %BRozłączono nas.%n\n disconnected %> %c%#%n %WRozłączono%n %R---| |---%n\n disconnected_descr %> %c%#%n %WRozłączono: %1%n %R---| |---%n\n during_connect %! %WŁączenie w toku...%n %k%xProszę czekać%n \n ekg_version %) EKG - Eksperymentalny Klient Gadu-Gadu (%W%1%n)\n%) Temat (C) 2002 by Arim.\n\n error %R%n error_adding %! %RBłąd podczas dodawania użytkownika%n\n error_adding_ignored %! %RPodany wpis już istnieje%n\n error_deleting %! %RUżytkownika nie ma na liście%n\n error_loading_theme %! %RŁadowanie tematu %W%1 %Rnie powiodło się!%n\n error_not_ignored %! %RPodana osoba nie jest ignorowana%n\n error_reading_config %! %RWystąpił błąd odczytu pliku z konfiguracją: %W%1%n\n error_saving %! %RWystąpił bład podczas zapisu konfiguracji!%n\n help %) %W%1%2%n %R->%n %3%4\n help_more %) %1\n ignored_added %> %WOd teraz ignorujesz%n %Y%1%n\n ignored_deleted %> %WOd teraz przestajesz ignorować %Y%1%n\n ignored_list %> ig: %1\n ignored_list_empty %> %WLista ignorów jest pusta%n\n invalid_uin %! %RNiewłaściwy numer%n %Wuin%n\n invisible %c%#%n %> %MJestem niewidzialny :)%n\n invisible_descr %c%#%n %> %MJestem niewidzialny: %1%n\n known_user %1 list_avail %gdostępn%@2%K... %G<+>%n %g%[12]1%n |%K%[,-15]3%n|\n list_avail_descr %gdostępn%@2%K... %G<+>%n %g%[12]1%n |%K%[,-15]3%n| %K[%5]%n\n list_busy %czajęt%@2%K..... %C%n %c%[12]1%n |%K%[,-15]3%n|\n list_busy_descr %czajęt%@2%K..... %C%n %c%[12]1%n |%K%[,-15]3%n| %K[%5]%n\n list_empty %> %WTwoja lista jest pusta%n\n list_not_avail %Kniedostępn%@2 %R<->%n %K%[12]1%n |%K...............%n|\n list_not_avail_descr %Kniedostępn%@2 %R<->%n %K%[12]1%n |%K...............%n| %K[%5]%n\n list_invisible %mniewidoczn%@2 %M<*>%n %m%[12]1%n |%K...............%n|\n list_invisible_descr %mniewidoczn%@2 %M<*>%n %m%[12]1%n |%K...............%n| %K[%5]%n\n modify_done %> %WDane zmienione%n\n not_connected %! %RNie jesteś połączony z serwerem!%n\n not_enough_params %! %RZa mało parametrów%n\n not_implemented %! %RTej funkcji jeszcze nie ma!%n\n offline_mode %> %WJesteś w tybie off-line!%n\n passwd %> %WHasło zostało zmienione.%n\n passwd_failed %! %RBłąd podczas zmiany hasła!%n\n passwd_timeout %! %RPrzekroczono limit czasu operacji zmiany hasła!%n\n private_mode_invalid %! Nieprawidłowa wartość\n private_mode_is_off %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n wyłączony\n private_mode_is_on %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n włączony\n private_mode_off %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n wyłączono\n private_mode_on %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n włączono\n prompt %W<%%>%n prompt2 %K<*>%n quick_list %) %gobecny%W/%czajęty%W/%Mniewidzialny%n\n%)%1\n quick_list_avail %g%1%n quick_list_busy %c%1%n quick_list_invisible %M%1%n quit %> %KNo to cześć...%n\n\n quit_descr %> %KNo to cześć...%n%W%1%n\n\n readline_more --<-- naciśnij [enter] -->-- readline_prompt <%> readline_prompt_away <*> readline_prompt_invisible <.> readline_prompt_query <%1>-> readline_prompt_win <%% win.%1> readline_prompt_away_win <* win.%1> readline_prompt_invisible_win <. win.%1> readline_prompt_query_win <%1/win.%2>-> register_failed %! %RBłąd podczas rejestracji%n\n register_pending %! %RRejestracja w toku%n\n register_timeout %! %RPrzekroczono limit czasu operacji rejestrowania%n\n registered_today %! %RJuż zarejestrowano jeden numer. Nie nadużywaj.%n\n remind %> %WHasło zostało wysłane.%n\n remind_failed %! %RBłąd podczas wysyłania hasła%n\n remind_timeout %! %RPrzekroczono limit czasu operacji wysłania hasła%n\n saved %> %WUstawienia zapisane.%n\n search_failed %! %RBłąd podczas przeszukiwania%n%W: %1%n\n search_not_found %! %RNie znaleziono nikogo o takich danych%n\n search_results_multi %W%7%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n search_results_multi_active %G<+>%n search_results_multi_busy %C%n search_results_multi_female %MK%n search_results_multi_inactive %R<->%n search_results_multi_male %BM%n search_results_multi_unknown ? search_results_single %W%7%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n search_results_single_active %G<+>%n search_results_single_busy %C%n search_results_single_female %MK%n search_results_single_inactive %R<->%n search_results_single_male %BM%n search_results_single_unknown ? search_stopped %) Nie to nie. Dalej nie szukam.\n search_timeout %! %RPrzekroczono limit czasu operacji szukania!%n\n show_status %> %WTwój status:%n %1 %2\n%> %WJesteś zalogowany na serwerze %g%3%W.%n\n show_status_avail %G<+>%n %gdostępny%n show_status_avail_descr %G<+>%n %gdostępny: %1%n show_status_busy %C%n %Czajęty%n show_status_busy_descr %C%n %Czajęty: %1%n show_status_invisible %M<*>%n %Mniewidoczny%n show_status_invisible_descr %M<*>%n %Mniewidoczny: %1%n show_status_not_avail %R<->%n %Kniedostępny%n show_status_not_avail_descr %R<->%n %Kniedostępny: %1%n show_status_private_off show_status_private_on %K[%n%Btylko dla przyjaciół%n%K]%n sms_chat EKG: %# chat %1: %2 sms_error %! %RBłąd podczas wysyłania sms'a!%n\n sms_failed %! %RSms do użytkownika%n %W%1%n %Rnie został dostarczony!%n\n sms_msg EKG: %# msg %1: %2 sms_sent %> %GSms dostarczony do użytkownika %n %W%1%n\n sms_unknown %! %W%1%n %Rnie ma podanego numeru we wpisie%n\n status_avail %c%#%n %> %g%[12]1%G<+>%n %gdostępn%@2%n \n status_avail_descr %c%#%n %> %g%[12]1%G<+>%n %gdostępn%@2%n %K[%3]%n \n status_busy %c%#%n %> %c%[12]1%C%n %czajęt%@2%n\n status_busy_descr %c%#%n %> %c%[12]1%C%n %czajęt%@2%n %K[%3]%n \n status_invisible %c%#%n %> %M%[12]1%M<*>%n %Mniewidoczn%@2%n \n status_invisible_descr %c%#%n %> %M%[12]1%M<*>%n %Mniewidoczn%@2%n %K[%3]%n \n status_not_avail %c%#%n %> %K%[12]1%R<->%n %Kniedostępn%@2%n\n status_not_avail_descr %c%#%n %> %K%[12]1%R<->%n %Kniedostępn%@2%n %K[%3]%n \n sysmsg_footer %R+------------%n\n sysmsg_header %R+----------------%n Gadu-gadu system message %R----------------%n\n sysmsg_line %R|%n %1\n sysmsg_line_width 72 theme_default %> %WUstawiono domyślny wygląd.%n\n theme_loaded %> %WTemat wczytany.%n %K(C) Arim%n\n timestamp |%H:%M| unknown_command %! %RNieznane polecenie%n%W:%n %W%0%1%n\n unknown_user %W[%n%W%1%n%W]%n user_added %> %WUżytkownik %K%1%n %Wzostał dodany%n\n user_deleted %> %WUżytkownik%n %K%1%n %Wzostał usunięty%n\n user_exists %! %WUżytkownik%n %K%1%n %Wjuż istnieje%n\n user_info %) %KPseudonim%n%W:%n %W%1%n\n%) %KNumer%n%W:%n %W%2%n\n%) %KStan%n%W:%n %3\n%) %KImię i nazwisko%n%W:%n %5 %6\n%) %KNumer telefonu%n%W:%n %8\n%)%K Numer IP%n%W:%n %4\n user_info_avail %gdostępn%@1%n user_info_avail_descr %gdostępn%@1%n [%2] user_info_busy %czajęt%@1%n user_info_busy_descr %czajęt%@1%n [%2] user_info_invisible %mniewidoczn%@1%n user_info_not_avail %Kniedostępn%@1%n user_info_not_avail_descr %Kniedostępn%@1%n [%2] user_not_found %! %RNie ma na liście użytkownika %W%1%n!\n user_not_given %! %RMusisz podać użytkownika!%n\n userlist_get_error %! %RBłąd podczas pobierania listy kontaktów!%n\n userlist_get_ok %) %WListę kontaktów wczytano z serwera.%n\n userlist_put_error %! %RBłąd podczas wysyłania listy kontaktów!%n\n userlist_put_ok %) %WListę kontaktów zachowano na serwerze.%n\n variable %> %K%[_25]1%w%2%n\n variable_invalid %! %Wset:%n %r[%1]%n <- zła wartość.\n variable_not_found %! %RNieznana zmienna%n%W:%n %K[%n%W%1%n%K]%n\n statusbar %c|%w%{time}%c|%w %c(%w%{?!nick uin}%{nick}%c/%{?away %w}%{?avail %W}%{?invisible %K}%{?notavail %k}%{uin}%c) (%wwin%c/%w%{window}%{?query %c:%W}%{query}%c)%w%{?activity %c(%wact%c/%w}%{activity}%{?activity %c)%w}%{?mail %c(%wmail%c/%w}%{mail}%{?mail %c)}%{?more %c(%Gwięcej%c)}%{?debug %c(%Cdebug%c)} ncurses_prompt_none > ncurses_prompt > ncurses_prompt_query %1> header %c..:: %w%{window}%c %{?query :: %c%{?query_away %w}%{?query_avail %W}%{?query_invisible %K}%{?query_notavail %k}%{query}%{?query_descr %c/%w%{query_descr}}%c %{?query_ip :: %wip%c/%w%{query_ip}%c}}%{?!query :: %c%wekg%c/%w%{version}%c :: %w%{url}%c}%c ::..%n # Variant specific formats chat_footer %W+------------%n\n chat_header %W+------------%n Chat with %W%1%n %c(%C%#%c/%C%2%c)%n %W------------%n\n chat_conference_header %W+---------%n Chat with %W%3/%1%n %c(%C%#%c/%C%2%c)%n %W---------%n\n chat_line %W|%n %1\n chat_line_width -6 message_footer %K+------------%n\n message_header %K+------------%n Mesg from %W%1%n %c(%C%#%c/%2)%n %K------------%n\n message_conference_header %K+---------%n Mesg from %W%3/%1%n %c(%C%#%c/%2)%n %K---------%n\n message_line %K|%n %1\n message_line_width -6 sent_footer %M+------------%n\n sent_header %M+------------%n Msg sent: %W%1%n %c(%C%#%c/%2)%n %M------------%n\n sent_conference_header %M+---------%n Msg sent: %W%3/%1%n %c(%C%#%c/%2)%n %M---------%n\n sent_line %M|%n %1\n sent_line_width -6 sent_line_first,irc %g%# <%n%2%G>%n %1\n sent_line,irc %1\n sent_line_width,irc -6 message_line_first,irc %g%3<%n%2%G>%n %1\n message_line,irc %1\n message_line_width,irc -6 chat_line_first,irc %g%3%C<%n%2%C>%n %1\n chat_line,irc %1\n chat_line_width,irc -6 ekg-1.9~pre+r2855/themes/dj.theme000066400000000000000000000224761174410337000165400ustar00rootroot00000000000000# Based on EKG theme by (Arim) # EKG theme by DJ. ack_delivered %) %#: %K ack/%1%n\n ack_queued %) %#: %K ack/%1 -queued-%n\n aliases_add %> %WDodano alias %Y%1%n\n aliases_append %> %WDodano do aliasu %Y%1%n\n aliases_del %> %WAlias %Y%1 %Wzostał usunięty%n\n aliases_exist %! %RAlias %W%1%n %Rjuż istnieje%n\n aliases_invalid %! %RNiewłaściwy parametr%n %C(help alias?)%n\n aliases_list %> %W%[8]1%n %K->%n %g%2%n\n aliases_list_empty %> %WBrak aliasów%n\n aliases_list_next %> %[8]3 %K=>%n %g%2%n\n aliases_noexist %! %RAlias %W%1%n %Rnie istnieje!%n\n already_connected %! %RJuż jesteś połączony!%n\n already_searching %> %RPrzeszukiwanie w toku%n %WWpisz:%n %yfind -stop%n %Waby przerwać...%n\n auto_away %> %c%#%n: %CPo%n %W%1%n %Crobię sobie przerwę%n\n auto_away_descr %> %c%#%n: %CPo%n %W%1%n %Crobię sobie przerwę: %2%n\n autosaved %> %WNastąpił autozapis ustawień.\n away %> %c%#%n: %cWracam za chwilę ... %n\n away_descr %> %c%#%n: %cWracam za chwilę: %1%n\n back %> %c%#%n: %gJestem z powrotem %n\n back_descr %> %c%#%n: %gJestem z powrotem: %1%n\n change %> %WZmieniłeś informacje w katalogu publicznym.%n\n change_failed %! %RBłąd podczas zmiany informacji w katalogu publicznym!%n\n change_not_enough_params %! %RPolecenie wymaga podania %Wwszystkich%n %Rparametrów!%n\n change_timeout %! %RPrzekroczono limit czasu operacji zmiany katalogu publicznego!%n\n chat_line_first %Y%#%W:%g%[,10]2%W:%n %1\n chat_conference_line_first %Y%#%W:%g%[,10]2%W:%n %1\n chat_line %1\n conn_broken %! %c%#%n: %W---/%n%r*%n%W/---%n %RPołączenie z serwerem przerwane%n\n conn_failed %! %BBłąd podczas łączenia:%n %W%1%n\n conn_stopped %! %BŁączenie przerwane!%n\n conn_timeout %! %BSerwer nie odpowiada. Spróbuj jeszcze raz.%n\n connected %> %c%#%n [%G OK %n] %W<-%n %GPołączono z serwerem%n\n connecting %> %WTrwa łączenie z serwerem...%n\n disconn_warning %! %BRozłączono nas.%n\n disconnected %> %c%#%n: %WRozłączono%n %R---| |---%n\n disconnected_descr %> %c%#%n: %WRozłączono: %1%n %R---| |---%n\n during_connect %! %WŁączenie w toku...%n %k%xProszę czekać%n \n ekg_version %) EKG - Eksperymentalny Klient Gadu-Gadu (%W%1%n)\n%) Temat (C) 2002 by dj.\n\n error %K:%r:%R:%n error_adding %! %RBłąd podczas dodawania użytkownika%n\n error_adding_ignored %! %RPodany wpis już istnieje%n\n error_deleting %! %RUżytkownika nie ma na liście%n\n error_loading_theme %! %RŁadowanie tematu %W%1 %Rnie powiodło się!%n\n error_not_ignored %! %RPodana osoba nie jest ignorowana%n\n error_reading_config %! %RWystąpił błąd odczytu pliku z konfiguracją: %W%1%n\n error_saving %! %RWystąpił bład podczas zapisu konfiguracji!%n\n help %) %W%1%2%n %R->%n %3\n help_more %) %1\n ignored_added %> %WOd teraz ignorujesz%n %Y%1%n\n ignored_deleted %> %WOd teraz przestajesz ignorować %Y%1%n\n ignored_list %> ig: %1\n ignored_list_empty %> %WLista ignorów jest pusta%n\n invalid_uin %! %RNiewłaściwy numer%n %Wuin%n\n invisible %> %c%#%n: %MJestem niewidzialny :)%n\n invisible_descr %> %c%#%n: %MJestem niewidzialny: %1%n\n known_user %1 list_avail %> %gdostępn%@2%n%K...%n %W<%n%G+%n%W>%n %g%[12]1%n |%K%[,-15]3%n|\n list_avail_descr %> %gdostępn%@2%n%K...%n %W<%n%G+%n%W>%n %g%[12]1%n |%K%[,-15]3%n| %K[%5]%n\n list_busy %> %czajęt%@2%n%K.....%n %W<%n%C?%n%W>%n %c%[12]1%n |%K%[,-15]3%n|\n list_busy_descr %> %czajęt%@2%n%K.....%n %W<%n%C?%n%W>%n %c%[12]1%n |%K%[,-15]3%n| %K[%5]%n\n list_empty %> %WTwoja lista jest pusta%n\n list_invisible %> %mniewidoczn%@2%n %W<%n%M*%n%W>%n %m%[12]1%n |%K...............%n|\n list_invisible_descr %> %mniewidoczn%@2%n %W<%n%M-%n%W>%n %m%[12]1%n |%K...............%n| %K[%5]%n\n list_not_avail %> %Kniedostępn%@2%n %W<%n%R-%n%W>%n %K%[12]1%n |%K...............%n|\n list_not_avail_descr %> %Kniedostępn%@1%n %W<%n%R-%n%W>%n %K%[12]1%n |%K...............%n| %K[%5]%n\n message_line_first %Y%#%W:%G%[,10]2%W:%n %1\n message_conference_line_first %Y%#%W:%G%[,10]2%W:%n %1\n message_line %1\n modify_done %> %WDane zmienione%n\n not_connected %! %RNie jesteś połączony z serwerem!%n\n not_enough_params %! %RZa mało parametrów%n\n not_implemented %! %RTej funkcji jeszcze nie ma!%n\n offline_mode %> %WJesteś w tybie off-line!%n\n passwd %> %WHasło zostało zmienione.%n\n passwd_failed %! %RBłąd podczas zmiany hasła!%n\n passwd_timeout %! %RPrzekroczono limit czasu operacji zmiany hasła!%n\n private_mode_invalid %! Nieprawidłowa wartość\n private_mode_is_off %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n wyłączony\n private_mode_is_on %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n włączony\n private_mode_off %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n wyłączono\n private_mode_on %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n włączono\n prompt %K:%g:%G:%n prompt2 %K:%c:%C:%n quick_list %) %gobecny%W/%czajęty%W/%Mniewidzialny%n\n%)%1\n quick_list_avail %g%1%n quick_list_busy %c%1%n quick_list_invisible %M%1%n quit %> %KNo to cześć...%n\n\n quit_descr %> %KNo to cześć...%n%W%1%n\n\n readline_more --<-- naciśnij [enter] -->-- readline_prompt <%> readline_prompt_away <*> readline_prompt_invisible <.> readline_prompt_query <%1>-> readline_prompt_win <%% win.%1> readline_prompt_away_win <* win.%1> readline_prompt_invisible_win <. win.%1> readline_prompt_query_win <%1/win.%2>-> register_failed %! %RBłąd podczas rejestracji%n\n register_pending %! %RRejestracja w toku%n\n register_timeout %! %RPrzekroczono limit czasu operacji rejestrowania%n\n registered_today %! %RJuż zarejestrowano jeden numer. Nie nadużywaj.%n\n remind %> %WHasło zostało wysłane.%n\n remind_failed %! %RBłąd podczas wysyłania hasła%n\n remind_timeout %! %RPrzekroczono limit czasu operacji wysłania hasła%n\n saved %> %WUstawienia zapisane.%n\n search_failed %! %RBłąd podczas przeszukiwania%n%W: %1%n\n search_not_found %! %RNie znaleziono nikogo o takich danych%n\n search_results_multi %> %W%7%[-10]1%n %K|%n %[10]3 %K|%n %6 %K|%n %[18]2 %K|%n %[4]5 %K|%n %c%[14]4%n\n search_results_multi_active %W<%G+%W>%n search_results_multi_busy %W<%C?%W>%n search_results_multi_inactive %W<%R-%W>%n search_results_multi_female %MK%n search_results_multi_male %BM%n search_results_multi_unknown - search_results_single %> %W%7%[-10]1%n %K|%n %[10]3 %K|%n %6 %K|%n %[18]2 %K|%n %[4]5 %K|%n %c%[14]4%n\n search_results_single_active %W<%G+%W>%n search_results_single_busy %W<%C?%W>%n search_results_single_female %MK%n search_results_single_inactive %W<%R-%W>%n search_results_single_male %BM%n search_results_single_unknown %Wbrak%n search_stopped %) Nie to nie. Dalej nie szukam.\n search_timeout %! %RPrzekroczono limit czasu operacji szukania!%n\n show_status %> %WTwój status:%n %1 %2\n%> %WJesteś zalogowany na serwerze %g%3%W.%n\n show_status_avail %W<%n%G+%n%W>%n %gdostępny%n show_status_avail_descr %W<%n%G+%n%W>%n %gdostępny: %1%n show_status_busy %W<%n%C?%n%W>%n %Czajęty%n show_status_busy_descr %W<%n%C?%n%W>%n %Czajęty: %1%n show_status_invisible %W<%n%M*%n%W>%n %Mniewidoczny%n show_status_invisible_descr %W<%n%M*%n%W>%n %Mniewidoczny: %1%n show_status_not_avail %W<%n%R-%n%W>%n %Rniedostępny%n show_status_private_off show_status_private_on %K[%n%Btylko dla przyjaciół%n%K]%n sms_chat EKG: %# chat %1: %2 sms_error %! %RBłąd podczas wysyłania sms'a!%n\n sms_failed %! %RSms do użytkownika%n %W%1%n %Rnie został dostarczony!%n\n sms_msg EKG: %# msg %1: %2 sms_sent %> %GSms dostarczony do użytkownika %n %W%1%n\n sms_unknown %! %W%1%n %Rnie ma podanego numeru we wpisie%n\n status_avail %> %c%#%n: %g%[12]1%n%W<%n%G+%n%W>%n %gdostępn%@2%n \n status_avail_descr %> %c%#%n: %g%[12]1%n%W<%n%G+%n%W>%n %gdostępn%@2%n %K[%3]%n \n status_busy %> %c%#%n: %c%[12]1%n%W<%n%C?%n%W>%n %czajęt%@2%n\n status_busy_descr %> %c%#%n: %c%[12]1%n%W<%n%C?%n%W>%n %czajęt%@2%n %K[%3]%n \n status_invisible %> %c%#%n: %M%[12]1%n%W<%n%M*%n%W>%n %Mniewidoczn%@2%n \n status_invisible_descr %> %c%#%n: %M%[12]1%n%W<%n%M*%n%W>%n %Mniewidoczn%@2%n %K[%3]%n \n status_not_avail %> %c%#%n: %K%[12]1%n%W<%n%R-%n%W>%n %Kniedostępn%@2%n\n status_not_avail_descr %> %c%#%n: %K%[12]1%n%W<%n%R-%n%W>%n %Kniedostępn%@2%n %K[%3]%n \n theme_default %> %WUstawiono domyślny wygląd.%n\n theme_loaded %> %WTemat wczytany.%n\n timestamp %H:%M unknown_command %! %RNieznane polecenie%n%W:%n %W%0%1%n\n unknown_user %1 user_added %> %WUżytkownik %K%1%n %Wzostał dodany%n\n user_deleted %> %WUżytkownik%n %K%1%n %Wzostał usunięty%n\n user_exists %! %WUżytkownik%n %K%1%n %Wjuż istnieje%n\n user_info %) %KPseudonim%n%W:%n %W%3%n\n%) %KNumer%n%W:%n %W%7%n\n%) %KStan%n%W:%n %8\n%) %KImię i nazwisko%n%W:%n %1 %2\n%) %KNumer telefonu%n%W:%n %5\n user_info_avail %gdostępn%@1%n user_info_avail_descr %gdostępn%@1%n [%2] user_info_busy %czajęt%@1%n user_info_busy_descr %czajęt%@1%n [%2] user_info_invisible %mniewidoczn%@1%n user_info_not_avail %Kniedostępn%@1%n user_info_not_avail_descr %Kniedostępn%@1%n [%2] user_not_found %! %RNie ma na liście użytkownika %W%1%n!\n user_not_given %! %RMusisz podać użytkownika!%n\n userlist_get_error %! %RBłąd podczas pobierania listy kontaktów!%n\n userlist_get_ok %) %WListę kontaktów wczytano z serwera.%n\n userlist_put_error %! %RBłąd podczas wysyłania listy kontaktów!%n\n userlist_put_ok %) %WListę kontaktów zachowano na serwerze.%n\n variable %> %K%[_20]1%n%W%2%n\n variable_invalid %! %Wset:%n %r[%1]%n <- zła wartość.\n variable_not_found %! %RNieznana zmienna%n%W:%n %K[%n%W%1%n%K]%n\n sent_line_first %Y%#%W:%m%[,10]2%W:%n %1\n sent_conference_line_first %Y%#%W:%m%[,10]2%W:%n %1\n sent_line %1\n ekg-1.9~pre+r2855/themes/eileen.theme000066400000000000000000000072101174410337000173710ustar00rootroot00000000000000# eileen.theme (c) by en 2002; # still `underconstruction` # TIME timestamp %H.%M theme_loaded %> %Ren%w.%rtheme%n %K(c)2002::en_at_irc.pl%n\n welcome %> \n%Rekg:wersja:%1%r (loaded en.theme)%n\n\n ekg_version %) %Rekg:%r(%W%1%n%r) %Rlibgadu-%1 %r(%Rprotokół %W%2%r, %Rklient %W%3%r)%n\n autosaved %> %KZapisano\n quit \n%Kbye...%n\n%n # USERS known_user %1%K.%K%[.7]2 # PROMPT prompt %K÷%n prompt2 %W÷%n error %Y§ %Yo%yo:%n readline_prompt  .oo:  readline_prompt_query <@:%1>  readline_prompt_away  .zz:  readline_prompt_invisible  .iv:  readline_prompt_win [%1] .oo:  readline_prompt_query_win <%2:%1>  readline_prompt_away_win [%1] .zz:  readline_prompt_invisible_win [%1] .iv:  readline_prompt_win_act [%1#%2] .oo:  readline_prompt_query_win_act <%2#%3:%1>  readline_prompt_away_win_act [%1#%2] .zz:  readline_prompt_invisible_win_act [%1#%2] .iv:  readline_more ÷ ----więcej---- \n # LIST list_avail %> %K:%n %G%[-40]1 %g:%Go%g:%n %K[%3]%n\n list_avail_descr %> %K:%n %G%[-40]1 %g:%Go%g:%n %K[%3]%n\n list_busy %> %K:%n %g%[-40]1 %K:%go%K:%n %K[%3] %n\n list_busy_descr %> %K:%n %g%[-40]1 %K:%go%K:%n %K[%3] %n\n list_not_avail %> %K.%n %K%[-40]1 %K:.:%n\n list_not_avail_descr %> %K.%n %K%[-40]1 %K:.:%n\n list_unknown %> %K.%n %R%[-40]1 %K:?:%n\n # CHAT chat_header %W÷%G-> %gchat%G@%g%1 %g÷ %K%2%n\n chat_line %g: %n %1\n chat_footer %g:%n\n chat_line_width -8 chat_timestamp %H:%M %Y+%m+%d # MSG message_header %W÷%G-> %Wmsg%G@%g%1n\n message_line %W. %n %1\n message_line_width -8 message_footer %W.%n\n message_timestamp %H:%M %Y+%m+%d # SENT sent_header %R<-%W÷ %rsent%R@ %R÷ %r%2 %n\n sent_footer %r:%n\n sent_line %r: %1%n\n sent_line_width -8 sent_timestamp %H.%M %Y+%m+%d # SYSTEM not_enough_params %! %KZa mało parametrów -> %Whelp %1%n\n invalid_uin %! %KNie ma takiego numeru :S\n user_not_found %! %K%1? Nie znaleziono%n\n not_implemented %! %K Nie zaimplementowane\n unknown_command %! %KNieznane polecenie %1%n\n group_empty %! Grupa %T%1%n jest pusta\n user_exists %! %K%1 już istnieje w liście kontaktów\n error_adding %! %KBłąd podczas dopisywania do listy kontaktów\n error_deleting %! %KBłąd podczas usuwania z listy kontaktów\n descr_too_long %! %KDługość opisu przekracza limit, uciętych znaków: %1%n\n error_adding_ignored %! %KBłąd podczas dodawania do listy ignorowanych\n error_not_ignored %! %K%1 nie jest na liście ignorowanych\n ignored_list_empty %! %KLista ignorowanych użytkowników jest pusta\n secure %W{szyfrowane}%n user_added %> %KDopisano %1 do listy kontaktów\n user_deleted %> %KUsunięto %1 z listy kontaktów\n away %> %K.%no%WO %Caway%n\n away_descr %> %K.%no%WO %Caway%c %1.%2%n\n back %> %K.%no%WO %Cdostępny%n\n back_descr %> %K.%no%WO %Cdostępny -> %c%1.%2%n\n invisible %> %K.%no%WO %Cukryty%n\n invisible_descr %> %K.%no%WO %Cukryty ->%n %c%1%n%2\n private_mode_is_on %> %K.%no%WO %rprivate -> %Ron%n\n private_mode_is_off %> %K.%no%WO %rprivate -> %Roff%n\n private_mode_on %> %K.%no%WO %rprivate -> %Ron%n\n private_mode_off %> %K.%no%WO %rprivate -> %Ron%n\n private_mode_invalid %! %KNieprawidłowa wartość\n help %> %R%1%r%2 - %3%4\n help_footer \n%> %KGwiazdka (%n*%K) oznacza, że można uzyskać więcej szczegółów%n\n\n help_quick %> %KWięcej informacji -> %n"docs/ULOTKA"%K lub %nhttp://ekg.chmurka.net/%K.\n\n$ help_more %) %K%1%n\n help_alias %) %K%1 jest aliasem%n\n ekg-1.9~pre+r2855/themes/emers.theme000066400000000000000000000053741174410337000172540ustar00rootroot00000000000000prompt %b:%W:%Y:%n prompt2 %Y:%W:%b:%n saved %>%yZapisane%)%w\n quit %>%yBye!%)%w\n help %> %1%b%2 %> %y%3%w\n theme_loaded \n%>%YEKG%w theme by %BEmers%r/%BAppendix%)%w\n\n known_user %b|%w%[9]1%b|%W%[7]2%b|%Y list_empty %>%yWyglada na to, ze nie masz zadnych kolegow%)%w\n list_avail %1%YDostepny %b|%R(%W%#%R)%b|%w\n list_busy %1%MZajety %b|%R(%W%#%R)%b|%w\n list_not_avail %1%R!%rdostepny%b|%R(%W%#%R)%b|%w\n away %>%wStatus%B: %YZajety%)%w\n back %>%wStatus%B: %YDostepny%)%w\n invisible %>%YStatus: %wNiewidoczny%)%w\n auto_away %>%yWyglada na to ze od %B%1 %wmin. jestes %rzajety%w. Powiadomie o tym innych%)%w\n status_avail %1%YDostepny %b|%R(%W%#%R)%b|%w\n status_busy %1%MZajety %b|%R(%W%#%R)%b|%w\n status_not_avail %1%R!%rdostepny%b|%R(%W%#%R)%b|%w\n message_header %1%yOczekujaca wiadomosc%R(%W%#%R)%w\n chat_header %1%yWiadomosc %R(%W%#%R)%w\n ack_queued %1%yWiadomosc dojdzie pozniej %R(%W%#%R)%w\n ack_delivered %1%yWiadomosc dotarla %R(%W%#%R)%w\n not_enough_params %>%yZa malo parametrow%)%w\n invalid_uin %>%yNieprawidlowy numer uzytkownika%)%w\n user_added %1 %yzostal dodany do listy%w\n error_adding %>%wWystapil blad podczas dodawania uzytkownika%)%w\n user_not_found %>%yNie znaleziono uzytkownika %R%1%)%w\n user_deleted %1 %yzostal usuniety z listy%w\n error_deleting %>%yWystapil blad podczas usuwania uzytkownika%)%w\n user_exists %>%yUzytkownik %R%1%y juz istnieje na liscie%)%w\n ignored_list %>%W%1%)%w\n ignored_list_empty %>%yTak sie sklada, ze %Ynie masz%y wrogow%)%w\n ignored_added %>%R%1%y dodany do listy ignorowanych osob%)%w\n error_adding_ignored %>%YDopisanie do listy ignorowanych osob nie powiodlo sie%)%w\n conn_broken %>%RPolaczenie zerwane%)%w\n error_reading_config %>%yWystapil blad przy probie odczytania konfiguracji%)%w\n connecting %>%yLacze sie z serwerem...%)%W\n connected %>%yPolaczono %R(%W%#%R)%w\n conn_falied %>%yPolaczenie nie powiodlo sie %R(%W%#%R)%w\n disconnected %>%yRozlaczono %R(%W%#%R)%w\n theme_loaded %>%yWczytano wyglad o nazwie %W%1%)%w\n error_loading_theme %>%yWystapil blad przy probie odczytania wygladu%)%w\n not_connected %>%yBrak polaczenia z serwerem%)%w\n variable %>%R%1 %) %Y%2%w\n variable_not_found %>%yNieznana zmienna %r%1%)%w\n variable_invalid %>%yNieprawidlowa wartosc zmiennej%)%w\n not_implemented %>%yTej funkcji jeszcze nie ma%)%w/n no_config %>%wNieprawidlowa konfiguracja. Wpisz:\n%Wset uin \n%Wset password \n%Wsave\n%yNastepnie wydaj polecenie:\n%Wconnect%w\n already_connected %>%yKlient jest juz polaczony%)%w\n during_connect %>%yLaczenie trwa%)%w\n search_falied %>%yWystapil blad podczas szukania %R%1%)%w\n search_not_found %>%yNie znaleziono%)%w\n unknown_command %>%yNieznane polecenie: %R%1%0%w\n already_searching %>%ySzukanie trwa. Poczekaj, albo uzyj %Wfind -stop%)%w\n ekg-1.9~pre+r2855/themes/extract.pl000077500000000000000000000005231174410337000171160ustar00rootroot00000000000000#!/usr/bin/perl # prosty skrypt wyciągający z ../src/themes.c wszystkie formaty pozwalając # na łatwą edycję. ziew. # $Id$ open(FOO, "../src/themes.c") || die("Nie wstanę, tak będę leżał!"); while() { chomp; next if (!/\tformat_add\("/); s/\/\* .* \*\///; s/.*format_add\("//; s/", *"/ /; s/", *1\);.*//; print "$_\n"; } ekg-1.9~pre+r2855/themes/feeg.theme000066400000000000000000000162321174410337000170420ustar00rootroot00000000000000# feeg theme # dla ekg (by wojtekka), trochę po angielsku, prompty są zrobione dla # konsoli ze znaczkami iso02. # kontakt z autorem themika: feeg@psychodelic.org # Podziękowania dla Komara i Wardena, za współudział przy testowaniu themika. # TODO # dcc_*, i userlist_* prompt %K÷%w-%K÷%n prompt2 %K÷%W=%K÷%n error %K×%rx%K×%n timestamp %H%M readline_prompt > readline_prompt_away [Zzz]> readline_more [more...] readline_prompt_invisible ° readline_prompt_query [%1] query_started %) %Kstarting query%n with: %1 (press %K^D%n to %Kfinish%n)\n query_finished \n%) finished %Kquery%n with %1\n known_user %Y%1%n% unknown_user %W%1%n list_avail %> [%Gonline%n] %[-22]1 [%K%3%n]\n list_avail_descr %> [%Gonline%n] %[-22]1 [%K%3%n] %K[%n%5%K]%n\n list_busy %> [%Ybusy%n] %[-22]1 [%K%3%n]\n list_busy_descr %> [%Ybusy%n] %[-22]1 [%K%3%n] %K[%n%5%K]%n\n list_not_avail %> [%Koffline%n] %[-22]1\n list_not_avail_descr %> [%Koffline%n] %[-22]1 %K[%n%5%K]%n\n quit \n%Kc-you%n soon :-)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%n theme_loaded %> %Kfeeg%w.theme\n%> welcome to the machine.\n #komunikaty: message_header %K˛¸. message .. from%n: %1 %K.. sent%n: [%#]\n message_line %K.%n %1\n message_footer %K´˝÷---- ­­- -- -%n\n chat_header %K˛¸. message .. from%n: %1 %K.. sent%n: [%#]\n chat_line %K.%n %1\n chat_footer %K´˝÷---- ­­- -- -%n\n ack_queued %> [%#]: delivering delayed for %1\n ack_delivered %> [%#]: message for %1 has been delivered\n status_avail %) %1 is [%Gonline%n]\n status_avail_descr %) %1 is [%Gonline%n] %K[%n%3%K]%n\n status_busy %) %1 is [%Ybusy%n]\n status_busy_descr %) %1 is [%Ybusy%n] %K[%n%3%K]%n\n status_not_avail %) %1 has %Klogged out%n\n status_not_avail_descr %) %1 has %Klogged out%n %K[%n%3%K]%n\n conn_broken %! [%#]: %Kconnection%n lost!\n conn_failed %! %Kconnection%n failed\n%! system said: %1\n saved %> %Kconfiguration%n saved\n error_saving %! saving %Kfailed%n (error?)\n not_enough_params %! wrong number of %Karguments%n\n invalid_uin %! invalid %Kuin%n\n offline_mode %! you're in %Koffline%n mode\n connecting %> trying to %Kconnect%n...\n connected %> %Wconnected%n\n disconnected %> %Kdisconnected%n\n disconnected_descr %> %Kdisconnected%n: %1\n error_loading_theme %! theme not loaded (good for us, %Khuhuhuuh%n)\n%! system said: %1\n variable_not_found %! unknown %Kvariable%n\n variable_invalid %! you've entered %Kinvalid%n value\n not_implemented %! not (yet) implemented\n no_config %! %Kekg%n seems to be %Kunconfigured%n try to enter:\n%) set uin \n%) set password \n%) save\n%) to %Wconnect%n enter: %Wconnect%n\n user_added %> %Kuser%n %1 added\n error_adding %! %Kuser%n %Wnot%n added (error occured)\n user_deleted %> %Kbye%n bye, %1...\n user_not_found %! %Kuser%n not found\n error_deleting %! %Kuser%n %Wnot%n deleted (error occured)\n user_exists %! %Kuser%n %1 already exists\n help %n%[-10]1 - %K%2%n %3\n help_more %1\n away %> [%#]: %Kyou're%n now [%Ybusy%n]\n away_descr %> [%#]: %Kyou're%n now [%Ybusy%n] %K[%n%1%K]%n\n back %> %Kwelcome%n back!\n back_descr %> %Kwelcome%n back! %K(%n%1%K)%n\n invisible %> [%#]: %Kyou're%n now [%Kinvisible%n]\n invisible_descr %> [%#]: %Kyou're%n now [%Kinvisible%n] %K[%n%1%K]%n\n not_connected %! sorry, you're %Knot connected%n\n%> use %Kconnect%n to log in.\n aliases_invalid %! invalid %Kalias%n\n aliases_list_empty %! no %Kaliases%n found\n aliases_list %> %[-20]1 %W==%n %K%2%n\n aliases_add %) new %Kalias%n %1\n aliases_del %) removed %Kalias%n %1\n aliases_exist %! %Kalias%n already exists\n aliases_noexist %1 no such %Kalias%n found\n show_status %) [%#]: %Kyou're%n %1%2\n show_status_avail [%Gonline%n] show_status_busy [%Ybusy%n] show_status_invisible [%Kinvisible%n] show_status_not_avail [%Koffline%n] show_status_private_on [%Bfriends only%n] config_changed $> do you want to keep this configuration [yes/no] ? config_unknown %! unknown %Kconfiguration%n changes has been found, results may vary\n private_mode_is_on %> _%Kfriends only%n_ mode on\n private_mode_is_off %> _%Kfriends only%n_ mode off\n private_mode_on %> _%Kfriends only%n_ turned to %Won%n\n private_mode_off %> _%Kfriends only%n_ turned to %Woff%n\n private_mode_invalid %> try: %Khelp private%n\n ignored_list %> %[_-41]1\n ignored_list_empty %> nobody's %Kignored%n\n ignored_added %> user %1 has been %Kadded%n to ignore list\n ignored_deleted %> user %1 has been %Kremoved%n from ignore list\n error_not_ignored %! user %1 hasn't been %Kadded%n to ignore list (error?)\n unknown_command %! %1: %Kcommand%n not found\n already_connected %! you're %Kalready%n connected\n during_connect %! connecting in %Kprogess%n, please wait\n sms_error %! error occurred while trying to send sms\n sms_unknown %! %1's mobile phone number is uknown\n sms_sent %) [%#] %Ksms%n sent\n sms_failed %! sending %Ksms%n to %1 was unsuccessfull\n search_failed %! error occurred while %Ksearching%n\n search_not_found %! %Ksorry%n, no matches\n already_searching %! searching in progess, be patient! (or stop with %Kfind -stop%n)\n search_results_multi_female %MF%n search_results_multi_male M search_results_single_active [%Gavailable%n] search_results_single_inactive [%Kunavailable%n] search_results_single_female %Mfemale%n search_results_single_male male search_results_single %) nick: %3\n%) uin: %1\n%) name: %2\n%) city: %4\n%) birth date: %5\n%) gender: %6\n no_processes %! no active %Kprocesses%n\n process_exit %) process %1 (%2) %Kreturned%n %3\n modify_done %> userlist %Kmodified%n\n user_info %) name%K...%n %1 %2\n%) nick%K...%n %3\n%) alias%K...%n %4\n%) phone number%K...%n %5\n%) group%K...%n %6\n #nowe ficzery register %> %Kregistered%n successfully, your new %Knumber%n is: %Y%1%n\n register_failed %! %Knot registered%n (error occurred)\n register_pending %! registration %Kin%n progress, please %Kwait%n\n register_timeout %! registration %Ktimed out%n\n remind %> you're %Kpassword%n has just been %Kmailed%n to you\n remind_failed %! password %Knot%n sent (error occurred)\n remind_timeout %! remind %Kpassword%n operation %Ktimed out%n\n passwd %> password %Kupdated%n\n passwd_failed %! password %Knot%n updated (error occurred)\n passwd_timeout password %Knot%n updated (operation %Ktimed out%n)\n #ewenty events_list_empty %! %Kno entries%n in events %Klist%n\n events_list %> on %K%1%n %W%2 %Y%3%n\n events_add %> %Kevent%n added\n events_exist %! %Kevent%n %1 already %Kexists%n for %2\n events_del %> %Kevent%n deleted\n events_del_flags %> flags %W%1%n deleted\n events_add_flags %> flags %W%1%n added\n events_noexist %! event %Kunknown%n\n events_del_noexist %! no such %Kevent%n for %2\n events_seq_not_found %! sequence %Knot found%n\n events_act_no_params %! %Ktoo few%n arguments\n events_act_toomany_params %! %Ktoo many%n arguments\n events_seq_incorrect %! sequence %Kincorrect%n\n #... config_line_incorrect %! ignoring %Kincorrect line%n in config file\n temporary_run_event %) starting %Kwith%n event %1\n autosaved %) settings %Kautosaved%n\n change_not_enough_params %! %Ktoo few%n arguments\n registered_today %! don't %Kabuse%n, one %Kregistration%n per day should be enough auto_away %> %Kauto-away%n after %1 of inactivity\n auto_away_descr %> %Kauto-away%n after %1 of inactivity %K[%n%2%K]%n\n ekg-1.9~pre+r2855/themes/fi9o.theme000066400000000000000000000212211174410337000167740ustar00rootroot00000000000000# Mieszanina kilku innych theme + moje wlasne upodobania. - fi9o-ekg.theme ack_delivered %) %#: %K ack/%1%n\n ack_queued %) %#: %K ack/%1 -queued-%n\n autosaved %> %WNastąpił autozapis ustawień.\n chat_line_first %R<%W%2%R> %n%1 chat_conference_line_first %R<%W%2%R> %n%1 chat_line %1\n conn_broken %! %c%W---/%n%r*%n%W/---%n %RPołączenie z serwerem przerwane%n\n conn_failed %! %BBłąd podczas łączenia:%n %W%1%n\n conn_stopped %! %BŁączenie przerwane!%n\n conn_timeout %! %BSerwer nie odpowiada. Spróbuj jeszcze raz.%n\n connected %> [%G OK %n] %W<-%n %GPołączono z serwerem%n\n connecting %> %WTrwa łączenie z serwerem...%n\n disconn_warning %! %BRozłączono nas.%n\n disconnected %> %WRozłączono%n %R---| |---%n\n disconnected_descr %> %WRozłączono: %1%n %R---| |---%n\n during_connect %! %WŁączenie w toku...%n %k%xProszę czekać%n \n ekg_version %) EKG - Eksperymentalny Klient Gadu-Gadu (%W%1%n)\n%) theme by fi9o i inni.\n\n error %K:%r:%R:%n error_adding %! %RBłąd podczas dodawania użytkownika.%n\n error_adding_ignored %! %RPodany wpis już istnieje!%n\n error_deleting %! %RUżytkownika nie ma na liście!%n\n error_loading_theme %! %RŁadowanie tematu %W%1 %Rnie powiodło się!%n\n error_not_ignored %! %RPodana osoba nie jest ignorowana.%n\n error_reading_config %! %RWystąpił błąd odczytu pliku z konfiguracją: %W%1%n\n error_saving %! %RWystąpił bład podczas zapisu konfiguracji!%n\n help %) %W%1%2%n %R->%n %3\n help_more %) %1\n ignored_added %> %WOd teraz ignorujesz%n: %Y%1%n\n ignored_deleted %> %WOd teraz przestajesz ignorować: %Y%1%n\n ignored_list %> ig: %1\n ignored_list_empty %> %WLista ignorów jest pusta.%n\n invalid_uin %! %RNiewłaściwy numer%n %Wuin%n\n known_user %1 list_avail %gdostępn%@2%K... %G<+>%n %g%[12]1%n |%K%[,-15]3%n|\n list_avail_descr %gdostępn%@2%K... %G<+>%n %g%[12]1%n |%K%[,-15]3%n| %K[%5]%n\n list_busy %czajęt%@2%K..... %C%n %c%[12]1%n |%K%[,-15]3%n|\n list_busy_descr %czajęt%@2%K..... %C%n %c%[12]1%n |%K%[,-15]3%n| %K[%5]%n\n list_empty %> %WTwoja lista jest pusta%n\n list_not_avail %Kniedostępn%@2 %R<->%n %K%[12]1%n |%K...............%n|\n list_not_avail_descr %Kniedostępn%@2 %R<->%n %K%[12]1%n |%K...............%n| %K[%5]%n\n list_invisible %mniewidoczn%@2 %M<*>%n %m%[12]1%n |%K...............%n|\n list_invisible_descr %mniewidoczn%@2 %M<*>%n %m%[12]1%n |%K...............%n| %K[%5]%n\n message_line_first %R<%W%2%R> %n%1 message_conference_line_first %R<%W%2%R> %n%1 message_line %1\n modify_done %> %WDane zmienione.%n\n not_connected %! %RNie jesteś połączony z serwerem!%n\n not_enough_params %! %RZa mało parametrów!%n\n not_implemented %! %RTej funkcji jeszcze nie ma!%n\n offline_mode %> %WJesteś w tybie off-line!%n\n passwd %> %WHasło zostało zmienione.%n\n passwd_failed %! %RBłąd podczas zmiany hasła!%n\n passwd_timeout %! %RPrzekroczono limit czasu operacji zmiany hasła!%n\n private_mode_invalid %! Nieprawidłowa wartość.\n private_mode_is_off %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n wyłączony.\n private_mode_is_on %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n włączony.\n private_mode_off %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n wyłączono.\n private_mode_on %> %K[%n%Btylko dla przyjaciół%n%K]%n%W:%n włączono.\n prompt %K:%g:%G:%n prompt2 %K:%c:%C:%n quick_list %) %gobecny%W/%czajęty%W/%Mniewidzialny%n\n%)%1\n quick_list_avail %g%1%n quick_list_busy %c%1%n quick_list_invisible %M%1%n quit %> %KNo to cześć...%n\n\n quit_descr %> %KNo to cześć...%n%W%1%n\n\n readline_more --<-- naciśnij [enter] -->-- readline_prompt <%> readline_prompt_away <*> readline_prompt_invisible <.> readline_prompt_query <%1>-> readline_prompt_win <%% win.%1> readline_prompt_away_win <* win.%1> readline_prompt_invisible_win <. win.%1> readline_prompt_query_win <%1/win.%2>-> register_failed %! %RBłąd podczas rejestracji%n.\n register_pending %! %RRejestracja w toku%n.\n register_timeout %! %RPrzekroczono limit czasu operacji rejestrowania%n.\n registered_today %! %RJuż zarejestrowano jeden numer. Nie nadużywaj.%n\n remind %> %WHasło zostało wysłane.%n\n remind_failed %! %RBłąd podczas wysyłania hasła%n.\n remind_timeout %! %RPrzekroczono limit czasu operacji wysłania hasła%n.\n saved %> %WUstawienia zapisane.%n\n search_failed %! %RBłąd podczas przeszukiwania%n%W: %1%n\n search_not_found %! %RNie znaleziono nikogo o takich danych!%n\n search_results_multi %> %W%7%[-10]1%n %K|%n %[10]3 %K|%n %6 %K|%n %[18]2 %K|%n %[4]5 %K|%n %c%[14]4%n\n search_results_multi_active %W<%G+%W>%n search_results_multi_busy %W<%C?%W>%n search_results_multi_inactive %W<%R-%W>%n search_results_multi_female %MK%n search_results_multi_male %BM%n search_results_multi_unknown - search_results_single %> %W%7%[-10]1%n %K|%n %[10]3 %K|%n %6 %K|%n %[18]2 %K|%n %[4]5 %K|%n %c%[14]4%n\n search_results_single_active %W<%G+%W>%n search_results_single_busy %W<%C?%W>%n search_results_single_female %MK%n search_results_single_inactive %W<%R-%W>%n search_results_single_male %BM%n search_results_single_unknown %Wbrak%n search_stopped %) Nie to nie. Dalej nie szukam.\n search_timeout %! %RPrzekroczono limit czasu operacji szukania!%n\n show_status %> %WTwój status:%n %1 %2\n%> %WJesteś zalogowany na serwerze %g%3%W.%n\n show_status_avail %W<%n%G+%n%W>%n %gdostępny%n show_status_avail_descr %W<%n%G+%n%W>%n %gdostępny: %1%n show_status_busy %W<%n%C?%n%W>%n %Czajęty%n show_status_busy_descr %W<%n%C?%n%W>%n %Czajęty: %1%n show_status_invisible %W<%n%M*%n%W>%n %Mniewidoczny%n show_status_invisible_descr %W<%n%M*%n%W>%n %Mniewidoczny: %1%n show_status_not_avail %W<%n%R-%n%W>%n %Rniedostępny%n show_status_private_off show_status_private_on %K[%n%Btylko dla przyjaciół.%n%K]%n sms_chat EKG: %# chat %1: %2 sms_error %! %RBłąd podczas wysyłania sms'a!%n\n sms_failed %! %RSms do użytkownika%n %W%1%n %Rnie został dostarczony!%n\n sms_msg EKG: %# msg %1: %2 sms_sent %> %GSms dostarczony do użytkownika %n %W%1%n\n sms_unknown %! %W%1%n %Rnie ma podanego numeru we wpisie%n\n status_avail %> %g%[12]1%n%W<%n%G+%n%W>%n %gdostępn%@2%n \n status_avail_descr %> %g%[12]1%n%W<%n%G+%n%W>%n %gdostępn%@2%n %K[%3]%n \n status_busy %> %c%[12]1%n%W<%n%C?%n%W>%n %czajęt%@2%n\n status_busy_descr %> %c%[12]1%n%W<%n%C?%n%W>%n %czajęt%@2%n %K[%3]%n \n status_invisible %> %M%[12]1%n%W<%n%M*%n%W>%n %Mniewidoczn%@2%n \n status_invisible_descr %> %M%[12]1%n%W<%n%M*%n%W>%n %Mniewidoczn%@2%n %K[%3]%n \n status_not_avail %> %K%[12]1%n%W<%n%R-%n%W>%n %Kniedostępn%@2%n\n status_not_avail_descr %> %K%[12]1%n%W<%n%R-%n%W>%n %Kniedostępn%@2%n %K[%3]%n \n theme_default %> %WUstawiono domyślny wygląd.%n\n theme_loaded %> %WTemat wczytany.%n\n timestamp %H:%M unknown_command %! %RNieznane polecenie%n%W:%n %W%0%1%n.\n unknown_user %1 user_added %> %WUżytkownik %K%1%n %Wzostał dodany.%n\n user_deleted %> %WUżytkownik%n %K%1%n %Wzostał usunięty.%n\n user_exists %! %WUżytkownik%n %K%1%n %Wjuż istnieje.%n\n user_info %) %KPseudonim%n%W:%n %W%3%n\n%) %KNumer%n%W:%n %W%7%n\n%) %KStan%n%W:%n %8\n%) %KImię i nazwisko%n%W:%n %1 %2\n%) %KNumer telefonu%n%W:%n %5\n user_info_avail %gdostępn%@1%n user_info_avail_descr %gdostępn%@1%n [%2] user_info_busy %czajęt%@1%n user_info_busy_descr %czajęt%@1%n [%2] user_info_invisible %mniewidoczn%@1%n user_info_not_avail %Kniedostępn%@1%n user_info_not_avail_descr %Kniedostępn%@1%n [%2] user_not_found %! %RNie ma na liście użytkownika %W%1%n!\n user_not_given %! %RMusisz podać użytkownika!%n\n userlist_get_error %! %RBłąd podczas pobierania listy kontaktów!%n\n userlist_get_ok %) %WListę kontaktów wczytano z serwera.%n\n userlist_put_error %! %RBłąd podczas wysyłania listy kontaktów!%n\n userlist_put_ok %) %WListę kontaktów zachowano na serwerze.%n\n variable %> %K%[_20]1%n%W%2%n\n variable_invalid %! %Wset:%n %r[%1]%n <- zła wartość.\n variable_not_found %! %RNieznana zmienna!%n%W:%n %K[%n%W%1%n%K]%n\n search_failed %! %RBłąd podczas przeszukiwania%n!%W: %1%n\n search_not_found %! %RNie znaleziono nikogo o takich danych%n!\n search_results_multi %W%7%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n search_results_multi_active %G:::%n search_results_multi_busy %C:::%n search_results_multi_female %MK%n search_results_multi_inactive %R:::%n search_results_multi_male %BM%n search_results_multi_unknown ? search_results_single %W%7%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n search_results_single_active %G:::%n search_results_single_busy %C:::%n search_results_single_female %MK%n search_results_single_inactive %R:::%n search_results_single_male %BM%n search_results_single_unknown ? search_stopped %) Nie to nie. Dalej nie szukam.\n search_timeout %! %RPrzekroczono limit czasu operacji szukania!%n\n sent_line_first %G<%W%2%G> %n%1 sent_conference_line_first %G<%W%2%G> %n%1 sent_line %1\n ekg-1.9~pre+r2855/themes/gophi.theme000066400000000000000000000005541174410337000172420ustar00rootroot00000000000000# $Id$ # # theme bazujący na podstawowym. zmiany: # - usunięcie numerka jeżeli użytkownik jest na liście ("gophi/1234" -> "gophi") # - zamiana tekstu "(szyfrowane)" na "(s)" # - ustawienie "<<" i ">>" w /last obok tekstu (żeby wygodniej się czytało) known_user %T%1%n secure %Y(s)%n last_list_in %) %n [%1] %2 %Y<<%n %3\n last_list_out %) %n [%1] %2 %G>>%n %3\n ekg-1.9~pre+r2855/themes/irc.theme000066400000000000000000000013321174410337000167040ustar00rootroot00000000000000# prosty przykład ircopodobnego wyświetlania wiadomości message_line_first %3 %G<%n%2%G>%n %1\n message_conference_line_first %3 %G<%n%2%G>%n %1\n message_line %1\n chat_line_first %3 %C<%n%2%C>%n %1\n chat_conference_line_first %3 %C<%n%2%C>%n %1\n chat_line %1\n sent_line_first %3 %G<%n%2%G>%n %1\n sent_conference_line_first %3 %G<%n%2%G>%n %1\n sent_line %1\n message_line_first,nc %G<%n%2%G>%n %1\n message_conference_line_first,nc %G<%n%2%G>%n %1\n message_line,nc %1\n chat_line_first,nc %C<%n%2%C>%n %1\n chat_conference_line_first,nc %C<%n%2%C>%n %1\n chat_line,nc %1\n sent_line_first,nc %G<%n%2%G>%n %1\n sent_conference_line_first,nc %G<%n%2%G>%n %1\n sent_line,nc %1\n ekg-1.9~pre+r2855/themes/jamzed.theme000066400000000000000000000024151174410337000174040ustar00rootroot00000000000000known_user %W%1%Y/%W%2 auto_away %> %c[%W Automatyczna zmiana stanu po %Y%1%W na%c ]%R:%c[%Y ZAJĘTY %c]%R:%c(%C%#%c)%n\n list_avail %> %1 %c[%G Aktywny%c ]%n\n list_busy %> %1 %c[%Y Zajęty%c ]%n\n list_not_avail %> %1 %c[%r Nieaktywny%c ]%n\n status_avail %> %c[%1%c]%R:%c[%W Zmienił%B[%Wa%B]%W tryb na %c]%R:%c[%G AKTYWNY %c]%R:%c(%C%#%c)%n\n status_busy %> %c[%1%c]%R:%c[%W Zmienił%B[%Wa%B]%W tryb na%c ]%R:%c[%Y ZAJĘTY %c]%R:%c(%C%#%c)%n\n status_not_avail %> %c[%1%c]%R:%c[%W Zmienił%B[%Wa%B]%W tryb na%c ]%R:%c[%r NIEAKTYWNY %c]%R:%c(%C%#%c)%n\n away %> %c[%W Zmiana stanu na %c]%R:%c[ %RZAJĘTY %c]%R:%c(%C%#%c)%n\n back %> %c[%W Zmiana stanu na %c]%R:%c[ %GAKTYWNY %c]%R:%c(%C%#%c)%n\n invisible %> %c[%W Zmiana stanu na%c ]%R:%c[ %WNIEWIDOCZNY %c]%R:%c(%C%#%c)%n\n message_header \n%c[%1%c]%R:%c(%C%#%c)%Y\n message_footer %n\n chat_header \n%c[%1%c]%R:%c(%C%#%c)%Y\n chat_footer %n\n ack_queued %> %c[%1%c]%R:%c[%W Wiadomość otrzyma później %c]%R:%c(%C%#%c)%n\n ack_delivered %> %c[%1%c]%R:%c[%W Wiadomość otrzymał%B[%Wa%B] %c]%R:%c(%C%#%c)%n\n prompt %M%P-%Y=%M%P>%n prompt2 %Y-%B=%Y-%R>%n error %R<%W=%R-%n theme_loaded \n%R<%Y[jamzed]%G@%Y[EKG theme%G|%Y03/10/01%G|%Y]%R> %G<%Y[%RPatryk Kuźmicz%Y]%G> %R<%Y[jamzed%G@%Yirc.pl]%R>%n\n saved %c[ %WUstawienia zostały zapisane %c]%n\n ekg-1.9~pre+r2855/themes/klith.theme000066400000000000000000000110521174410337000172420ustar00rootroot00000000000000prompt %c-+-%n prompt2 %K-+-%n error %R-+-%n readline_prompt_away ! readline_prompt % known_user %1 unknown_user %1 user_not_given %! podaj użytkownika.\n not_enough_params %! za mało parametrów.\n unknown_command %! %1%0: hę?.. dunno :/\n saved %> ustawienia zapisane!\n error_saving %! bład podczas zapisu konfiguracji.\n error_reading_config %! nie mogę odczytać pliku z konfiguracją.\n quit %> na ryby!\n help %> %[10]1 -> %Y%2%w %3\n help_more %) %1\n theme_loaded %# %> %Wtheme:%n dzzzzz wcytane :)\n theme_default %# %> %Wtheme:%n ustawiony domyślny wygląd.\n error_loading_theme %# %! %Wtheme:%n błąd podczas ladowania.\n user_info %> kont.: %W%4%n / %3 (%1 %2) / %5\n modify_done %> kont.: zmieniono wpis.\n search_results_single_active %G*%n search_results_single_inactive %r!%n search_results_single_female k search_results_single_male m search_results_single %7 %[-10]1 %K/%n %[12]3 %K/%n %6 %K/%n %[20]2 %K/%n %[4]5 %K/%n %[16]4\n already_searching %> trwa jedno przeszukiwanie, uzyj find -stop aby przerwac..\n search_falied %! zonk podczas szukania: %1\n search_not_found %! nic nie znalazlem..\n list_empty %> nikt Cie nie kocha..\n list_avail %G*%n %[12]1 %G*%n %[15]3 %[-4]4 %G*%n\n list_avail_descr %G*%n %[12]1 %G*%n %[15]3 %[-4]4 %G*%n %5\n list_busy %g/%n %[12]1 %g/%n %[15]3 %[-4]4 %g/%n\n list_busy_descr %g/%n %[12]1 %g/%n %[15]3 %[-4]4 %g/%n %5\n list_not_avail %r!%n %[12]1 %r!%n\n list_not_avail_descr %r!%n %[12]1 %r!%n %[15]3 %[-4]4 %r!%n %5\n list_invisible %c:%n %[12]1 %c:%n %[15]3 %[-4]4 %c:%n\n away %# %> status: %g/ %Wzajęty%n\n away_descr %# %> status: %g/ %Wzajęty%n: %1\n back %# %> status: %G* %Wdla ludu!%n\n back_descr %# %> status: %G* %Wdla ludu%n: %1\n invisible %# %> status: %c: %Wchowamy się!?%n\n invisible_descr %# %> status: %c: %Wchowamy się:%n %1\n auto_away %# %> *auto-away* po %W%1%n\n status_avail %# %> %[10]1 %G* %Wdla ludu!%n\n status_avail_descr %# %> %[10]1 %G* %Wdla ludu%n: %3\n status_busy %# %> %[10]1 %g/ %Wzajęt%@2%g /%n\n status_busy_descr %# %> %[10]1 %g/ %Wzajęt%@2%n: %3 %g/%n\n status_not_avail %# %> %[10]1 %R! %Wzdechł pies%n\n status_not_avail_descr %# %> %[10]1 %R! %WR.I.P.%n: %3\n status_invisible %# %> %[10]1 %c: %Wniewidoczn%@2%n\n show_status %> status: %1\n show_status_avail %G*%n dla ludu! show_status_avail_descr %G*%n dla ludu: %1 show_status_busy %g/%n zZzz show_status_busy_descr %g/%n zZzz: %1 show_status_invisible %c*%n niewidoczny.. show_status_invisible_descr %c*%n niewidoczny: %1 show_status_not_avail %R!%n niepołączny message_header %b%x %1: (%#/%2) %n\n message_footer \n message_line %1\n message_line_width 75 chat_header %> %W%1%n: %c(%C%#%n/%2%c)%n\n chat_footer - chat_line %1\n chat_line_width 75 ack_queued %) %K ack/%1 (%#) nie ma typa capish ?!%n\n ack_delivered %) %K ack/%1 (%#)%n\n sms_sent %> sms do %1 został wysłany.\n sms_failed %! sms do %1 raczej nie dotarł :).\n sms_error %! sms: błąd podczas wysyłania sms'a.\n sms_unknown %! sms: %1 <- kolo nie ma podanego numeru we wpisie.\n variable %> %[,25]1%2\n variable_not_found %! %Wset:%n [%1] <- dunno.\n variable_invalid %! %Wset:%n [%1] <- zla wartość.\n ignored_list %> ig: %1\n ignored_list_empty %> bzzz, lista ignorów pusta :)\n ignored_added %> dodany kolejny jeleń.. %W%1%n\n ignored_deleted invalid_uin %! nipoprawny uin.\n user_added %> kont.: dodano %W%1%n.\n user_not_found %! kont.: nie mam %W%1%n na lisice.\n user_deleted %> kont.: usunieto %W%1%n.\n user_exists %! kont.: uzytkownik %W%1%n juz istnieje.\n error_adding %! użytkownik nie został dodany.\n error_deleting %! nie ma nikogo takiego na liście \n error_adding_ignored %! heh koleś ma niezłe kredki :) (wpis istnieje)\n error_not_ignored %! tego typa jeszce nikt nie zaczął ignorować\n conn_broken %! %# przerwane połącznie\n connecting %> dzzz konekting..\n during_connect %! lączenie w toku..\n connected %> %WOK.%n brum brum.. (%#)\n conn_falied %! %Wzonk:%n przy połączeniu: %1\n disconnected %> %# *pufff* <-: :->\n not_connected %> nie jesteś połączony..\n already_connected %! jesteś już połączony..\n offline_mode %! jesteś w tybie off-line!\n error_reading_config %! błąd podczał czytania konf.\n no_config %> nieprawidlowa konfiguracja. wpisz:\n%Wset uin \n%Wset password \n%Wsave\n%ynastepnie wydaj polecenie:\n%Wconnect%w\n aliases_list %> alias %[8]1 [%K%2%n].\n aliases_add %> alias %W%1%n -> %2.\n aliases_del %> usunieto alias %W%1%n.\n aliases_exist %! %W%1%n: taki alias już istnieje.\n aliases_noexist %! %W%1%n: nie ma takiego aliasa.\n aliases_list_empty %> nie masz żadnych aliasów.\n aliases_invalid %! zły parametr, (help alias ?)...\n ekg-1.9~pre+r2855/themes/krzyk.theme000066400000000000000000000600161174410337000173050ustar00rootroot00000000000000# EKG theme by krzyk # based on: sic!, z duza iloscia zmian prompt %b->%n prompt,speech prompt2 %b *%n prompt2,speech error %R-!%n error,speech błąd! timestamp %H:%M:%S timestamp,speech ncurses_prompt_none ncurses_prompt_query [%1] statusbar %c%{time} (GG#%{?away %w}%{?avail %W}%{?invisible %C}%{?notavail %K}%{uin}%n%w) (win/%{window}%{?query %c:%W}%{?query_away %c}%{?query_avail %W}%{?query_notavail %K}%{?query_invisible %C}%{query}%c)%W %{?activity %c(%Wact%c/%W}%{activity}%{?activity %c)%n} header %{?query %{?query_away %wzajęty}%{?query_avail %Wdostępny}%{?query_notavail %Kniedostępny}%{?query_invisible %Cniewidoczny}%{?query_descr : %{query_descr}}}%{?!query %{?away %wzajęty}%{?avail %Wdostępny}%{?notavail %Kniedostępny}%{?invisible %Cniewidoczny}%{?descr : %{descr}}}%n known_user %1 known_user,speech %1 unknown_user %n[%r%1%n] none %1\n generic %> %1\n generic2 %) %1\n generic_error %! %1\n debug %n%1\n not_enough_params %! %RZa mało parametrów%n \n invalid_params %! Nieprawidłowe parametry. Spróbuj %Whelp %1%n\n invalid_uin %! %RNiewłaściwy numer%n %Wuin%n \n invalid_nick %! %RNiewłaściwa nazwa użytkownika%n\n user_not_found %! %RNie ma na liście użytkownika%n %W%1%n\n not_implemented %! Tej funkcji jeszcze nie ma\n unknown_command %! %RNieznane polecenie%n: %W%0%1%n\n welcome %> %TEKG-%1%n (Eksperymentalny Klient Gadu-Gadu)\n%> Program jest rozprowadzany na zasadach licencji GPL v2\n%> %RPrzed użyciem wciśnij F1 lub wpisz ,,help''%n\n\n welcome,speech witamy w e k g ekg_version %) EKG - Eksperymentalny Klient Gadu-Gadu (%T%1%n)\n%) libgadu-%1 (protokół %2, klient %3)\n%) skompilowano: %4\n secure %y(szyfrowane)%n new_mail_one %) Masz nową wiadomość email\n new_mail_two_four %) Masz %1 nowe wiadomości email\n new_mail_more %) Masz %1 nowych wiadomości email\n user_added %> Użytkownik %W%1%n został dodany\n user_deleted %> Użytkownik %W%1%n został usunięty\n user_cleared_list %> Wyczyszczono listę kontaktów\n user_exists %! %W%1%n %Rjuż istnieje w liście kontaktów%n\n user_exists_other %! %W%1%n %Rjuż istnieje w liście kontaktów jako%n %W%2%n\n error_adding %! %RBłąd podczas dodawania użytkownika%n\n error_deleting %! %RUżytkownika nie ma na liście%n\n away %r%#%n %> %wAway: wracam za chwilę ... %n\n away_descr %r%#%n %> %wAway: %1%n\n back %r%#%n %> %WJestem z powrotem %n\n back_descr %r%#%n %> %WJestem z powrotem: %1%n\n invisible %r%#%n %> %CJestem niewidzialny%n\n invisible_descr %r%#%n %> %CJestem niewidzialny: %1%n\n private_mode_is_on %> Tryb %Wtylko dla przyjaciół%n jest %rwłączony%n \n private_mode_is_off %> Tryb %Wtylko dla przyjaciół%n jest %Kwyłączony%n \n private_mode_on %> Włączono tryb %Wtylko dla przyjaciół%n \n private_mode_off %> Wyłączono tryb %Wtylko dla przyjaciół%n \n private_mode_invalid %! %RZła wartość!%n prawidłowa składnia to: %Wprivate%n %yon%n%W|%n%yoff%n\n descr_too_long %! %RDługość opisu przekracza limit.%n Ilość uciętych znaków: %W%1%n\n help %> %[10]1 -> %W%2%n %3\n help_more %) %|%1%n\n help_alias %) %W%1%n jest aliasem i nie posiada opisu\n help_footer \n%> Gwiazdka (%W*%n) oznacza, że można uzyskać więcej szczegółów%n\n%> Poprzedzenie komendy znakiem %W^%n powoduje ukrycie jej wyniku%n\n\n help_quick %> %|Przed użyciem przeczytaj ulotkę. Plik %Wdocs/ULOTKA%n zawiera krótki przewodnik po załączonej dokumentacji. Jeśli go nie masz, możesz ściągnąć pakiet ze strony %Whttp://ekg.chmurka.net/%n\n help_set_file_not_found %! %RNie znaleziono opisu zmiennych (nieprawidłowa instalacja)\n help_set_var_not_found %! %RNie znaleziono opisu zmiennej %W%1%n \n help_set_header %> %W%1%n (%2, domyślna wartość: %W%3%n)\n%>%n \n help_set_body %) %|%1%n \n help_set_footer ignored_added %> Od teraz ignorujesz %W%1%n\n ignored_deleted %> Skasowano%n %W%1%n z listy ignorów\n ignored_deleted_all %> Skasowano%n wszystkich z listy ignorów\n ignored_exist %! %1 jest już ignorowany\n ignored_list %> ig: %1\n ignored_list_empty %> Lista ignorów jest pusta\n error_not_ignored %! %RPodana osoba nie jest ignorowana%n \n blocked_added %> Dodano %W%1%n do listy blokowanych \n blocked_deleted %> Usunięto %W%1%n z listy blokowanych \n blocked_deleted_all %> Usunięto wszystkich z listy blokowanych \n blocked_list %> %1\n blocked_list_empty %! Lista blokowanych użytkowników jest pusta\n error_not_blocked %! %W%1%n %Rnie jest na liście blokowanych %n\n list_empty %> Twoja lista jest pusta \n list_avail %n [%W+%n] %W%[14]1%n [%K%[,-15]3%n] %W...%n \n list_avail_descr %n [%W+%n] %W%[14]1%n [%K%[,-15]3%n] %W%5%n \n list_busy %n [%w?%n] %w%[14]1%n [%K%[,-15]3%n] %w...%n \n list_busy_descr %n [%w?%n] %w%[14]1%n [%K%[,-15]3%n] %w%5%n \n list_not_avail %n [%K-%n] %K%[14]1%n [%K%[,-15]3%n] %K...%n \n list_not_avail_descr %n [%K-%n] %K%[14]1%n [%K%[,-15]3%n] %K%5%n \n list_invisible %n [%C*%n] %C%[14]1%n [%K%[,-15]3%n] %C...%n \n list_invisible_descr %n [%C*%n] %C%[14]1%n [%K%[,-15]3%n] %C%5%n \n list_blocked %n [%m!%n] %m%[14]1%n [%K%[,-15]3%n] %mblokując%@2%n \n list_unknown %n [%R%%%n] %R%[14]1%n [%K%[,-15]3%n] %Rnieznan%@2%n \n modify_offline %> %W%1%n nie będzie widzieć naszego stanu \n modify_online %> %W%1%n będzie widzieć nasz stan \n modify_done %> Dane zmienione \n contacts_header contacts_header_group %b_%r%1%n%b__________________________________________%n contacts_avail_header contacts_avail %W%1%n contacts_avail_descr %ri%n%W%1%n contacts_avail_descr_full %ri%n%W%1%n: %K%2%n contacts_avail_footer %b-------------------------------------------------%n contacts_busy_header contacts_busy %w%1%n contacts_busy_descr %ri%n%w%1%n contacts_busy_descr_full %ri%n%w%1%n: %K%2%n contacts_busy_footer %b-----------------------------------------------%n contacts_not_avail_header contacts_not_avail %K%1%n contacts_not_avail_descr %ri%n%K%1%n contacts_not_avail_descr_full %ri%n%K%1%n: %K%2%n contacts_not_avail_footer %b-----------------------------------------------%n contacts_invisible_header contacts_invisible %C%1%n contacts_invisible_descr %ri%n%C%1%n contacts_invisible_descr_full %ri%n%C%1%n: %K%2%n contacts_invisible_footer %b-----------------------------------------------%n contacts_blocking_header contacts_blocking %m%1%n contacts_blocking_footer %b-----------------------------------------------%n contacts_footer contacts_footer_group quit %> %WP%n%wa%n%Kp%n%Ka%n %W....%n\n\n quit_descr %> %WP%n%wa%n%Kp%n%Ka%n %W....%1%n%2\n\n config_changed Zapisać nową konfigurację? (tak/nie) saved %r%#%n %> %WZapisano !%n\n error_saving %!%RWystąpił bład podczas zapisu konfiguracji%n\n message_header %w%n %W%1%n %K[%#]%n \n message_conference_header %g.-- %g[%T%3%g] -- %n%1 %c%2%4%g--- -- -%n\n message_footer message_line %1\n message_line_width -8 message_timestamp (%Y-%m-%d %H:%M) message_timestamp_today (%H:%M) message_timestamp_now message_header,speech wiadomość od %1: message_conference_header,speech wiadomość od %1 w konferencji %3: message_line,speech %1\n message_footer,speech . chat_header %w%n %W%1%n %K[%#]%n \n chat_conference_header %c.-- %c[%T%3%c] -- %n%1 %c%2%4%c--- -- -%n\n chat_footer chat_line %1\n chat_line_width -8 chat_timestamp (%Y-%m-%d %H:%M) chat_timestamp_today (%H:%M) chat_timestamp_now chat_header,speech wiadomość od %1: chat_conference_header,speech wiadomość od %1 w konferencji %3: chat_line,speech %1\n chat_footer,speech . sent_header %w%n %W%1%n %K[%#]%n \n sent_conference_header %W%1 [%#]%n\n sent_footer sent_line %K%1%n \n sent_line_width -8 sent_timestamp %H:%M sysmsg_header %R*%n %cGadu-Gadu: wiadomość systemowa%n %R*%n\n sysmsg_line %R|%n %1\n sysmsg_line_width -8 sysmsg_footer %R*%n %c --- %n %R*%n\n sysmsg_header,speech wiadomość systemowa: sysmsg_line,speech %1\n sysmsg_footer,speech . ack_queued %) %K ack|%1 %K(%n%c%#%n%K)%n -dodano do kolejki-%n \n ack_delivered %) %K ack|%1 %K(%n%c%#%n%K) -dostarczono-%n \n ack_filtered %! %|Wiadomość do %1 najprawdopodobniej nie została dostarczona, ponieważ dana osoba jest niedostępna, a serwer twierdzi, że doręczył wiadomość. Sytuacja taka ma miejsce, gdy wiadomość została odrzucona przez filtry serwera (np. zawiera adres strony WWW)\n ack_filtered_short %! %|Wiadomość do %1 najprawdopodobniej nie została dostarczona\n message_too_long %! %RWiadomość jest zbyt długa i została skrócona%n \n status_avail %r%#%n %> %W%[14]1%n [%W+%n] %Wdostępn%@2%n \n status_avail_descr %r%#%n %> %W%[14]1%n [%W+%n] %W%3%n \n status_busy %r%#%n %> %w%[14]1%n [%w?%n] %wzajęt%@2%n \n status_busy_descr %r%#%n %> %w%[14]1%n [%w?%n] %w%3%n \n status_not_avail %r%#%n %> %K%[14]1%n [%K-%n] %Kniedostępn%@2%n \n status_not_avail_descr %r%#%n %> %K%[14]1%n [%K-%n] %K%3%n \n status_invisible %r%#%n %> %C%[14]1%n [%C*%n] %Cniewidoczn%@2%n \n status_invisible %r%#%n %> %C%[14]1%n [%C*%n] %C%3%n \n auto_away %r%#%n %> Po %W%1%n robię sobie przerwę \n auto_away_descr %r%#%n %> Po %W%1%n robię sobie przerwę: %w%2%n%3 \n auto_back %> Automagicznie zmieniono stan na dostępny\n auto_back_descr %> Automagicznie zmieniono stan na dostępny: %W%2%n%3\n connecting %> %wTrwa łączenie z serwerem...%n \n conn_failed %! %RBłąd podczas łączenia:%n %W%1%n \n conn_failed_resolving Nie znaleziono serwera conn_failed_connecting Nie można połączyć się z serwerem conn_failed_invalid Nieprawidłowa odpowiedź serwera conn_failed_disconnected Serwer zerwał połączenie conn_failed_password Nieprawidłowe hasło conn_failed_404 Błąd serwera HTTP conn_failed_memory Brak pamięci conn_stopped %! %RPrzerwano łączenie %n\n conn_timeout %! %RPrzekroczono limit czasu operacji łączenia z serwerem %n\n connected %r%#%n %> %WPołączono z serwerem%n \n connected_descr %r%#%n %> Połączono z serwerem: %W%1%n%2\n disconnected %r%#%n %> %WRozłączono%n \n disconnected_descr %> %r%#%n %WRozłączono%n: %K%1%n%2\n already_connected %! %RJuż jesteś połączony%n\n during_connect %! Łączenie w toku... %WProszę czekać%n \n conn_broken %! %r%#%n %R--/%n%r*%n%W/---%n %RPołączenie z serwerem przerwane%n\n conn_disconnected %! %r%#%n %R--/%n%r*%n%W/---%n %RSerwerem zerwał połączenie%n\n not_connected %! %RNie jesteś połączony z serwerem%n\n not_connected_msg_queued %! %RNie jesteś połączony z serwerem. Wiadomość będzie wysłana po połączeniu.%n\n theme_loaded %r%#%n %> theme wczytany %Kk%n%wr%n%Wz%n%wy%n%Kk%n \n theme_default %r%#%n %> Ustawiono domyślny wygląd\n error_loading_theme %r%#%n %! %RŁadowanie theme'a nie powiodło się%n\n variable %> %[,25]1%W%2%n\n variable_not_found %! %RNieznana zmienna%n %K[%n %W%1%n %K]%n\n variable_invalid %! set %W%1%n : %Rzła wartość.%n \n no_config %! %RUwaga! Nieprawidłowa konfiguracja.%n Zrób tak: %Wwpisz:%n\n%cset uin%n %W%n\n%cset password%n %W%n\n%csave%n\n%cconnect%n\n no_config,speech niekompletna konfiguracja. wpisz set uin, a potem numer gadu-gadu, potem set pasłord, a za tym swoje hasło. wpisz sejf, żeby zapisać ustawienia. wpisz konekt by się połączyć. jeśli nie masz swojego numeru gadu-gadu, wpisz redżister, a po spacji imejl i hasło. error_reading_config %!%RWystąpił błąd odczytu pliku z konfiguracją%n\n config_read_success %> Wczytano plik konfiguracyjny %W%1%n \n autosaved %> %WAutomatycznie zapisano ustawienia %n\n register %> Rejestracja poprawna. Wygrany numerek: %W%1%n\n register_failed %! %RBłąd podczas rejestracji: %W%1%n\n register_pending %! %RRejestracja w toku%n\n register_timeout %! %RPrzekroczono limit czasu operacji rejestrowania%n\n registered_today %! %RJuż zarejestrowano jeden numer. Nie nadużywaj%n\n unregister %> Konto %W%1%n wykasowane.%n\n unregister_timeout %! %RPrzekroczono limit czasu operacji usuwania konta%n\n unregister_bad_uin %! %RNie poprawny numer: %W%1%n\n unregister_failed %! %RBłąd podczas usuwania konta: %W%1%n\n remind %> %WHasło zostało wysłane%n\n remind_failed %! %RBłąd podczas wysyłania hasła: %W%1%n\n remind_timeout %! %RPrzekroczono limit czasu operacji wysłania hasła%n\n passwd %> %WHasło zostało zmienione%n\n passwd_failed %! %RBłąd podczas zmiany hasła: %W%1%n\n passwd_timeout %! %RPrzekroczono limit czasu operacji zmiany hasła%n\n change_not_enough_params %! %RNie podano wszystkich wymaganych parametrów%n\n change %> %WInformacje w katalogu publicznym zostały zmienione%n\n change_failed %! %RBłąd podczas zmiany informacji w katalogu publicznym: %W%1%n\n change_timeout %! %RPrzekroczono limit czasu operacji zmiany katalogu publicznego%n\n sms_error %! %RBłąd podczas wysyłania sms'a%n\n sms_unknown %! %W%1%n %Rnie ma ustawionego numeru%n\n sms_sent %> %WWysłano sms'a do%n %K%1%n\n sms_failed %! %RSms do%n %W%1%n %Rnie został dostarczony%n\n sms_msg EKG: msg %1 %# >> %2 sms_chat EKG: chat %1 %# >> %2 sms_conf EKG: conf %1 %# >> %2 search_falied %! %RBłąd podczas przeszukiwania%n: %W%1%n\n search_timeout %! %RPrzekroczono limit czasu operacji szukania!%n\n search_not_found %! %RNie znaleziono nikogo o takich danych%n\n search_no_last %! %RBrak wyników ostatniego wyszukiwania%n \n search_no_last_nickname %! %RBrak pseudonimu w ostatnim wyszukiwaniu%n \n search_stopped %> Zatrzymano wyszukiwanie\n search_results_multi_active <%W+%n> search_results_multi_busy <%w?%n> search_results_multi_invisible <%C*%n> search_results_multi_inactive <%K-%n> search_results_multi_unknown %% search_results_multi_female %MK%n search_results_multi_male %BM%n search_results_multi %7%K%[-10]1%n %w|%n %K%[12]3%n %w|%n %K%6%n %w|%n %K%[20]2%n %w|%n %K%[4]5%n %w|%n %K%[16]4%n\n search_results_single_active %Wdostępny%n search_results_single_busy %wzajęty%n search_results_single_inactive %Kniedostępny%n search_results_single_invisible %Cniewidzialny%W>%n search_results_single_unknown %% search_results_single_female %MK%n search_results_single_male %BM%n search_results_single %KStan%n : %7\n %KNumerek%n : %1%n %K\n%n %KNick%n : %3 %K\n%n %KImie%n : %2 %K\n%n %KRok ur.%n : %[4]5 %K\n%n %KMiasto%n : %4%n\n process %> %W%(-5)1 %2%n\n no_processes %! %RNie ma działających procesów%n \n process_exit %> Proces %W%1%n (%2) zakończył działanie z wynikiem %3\n exec %1\n exec_error %! %RBłąd uruchamiania procesu:%n %W%1%n \n #user_info %) %KWyświetlany%n%W:%n %W%7%n\n%) %KPseudonim%n%W:%n %W%1%n\n%) %KNumer%n%W:%n %W%2%n\n%) %KStan%n%W:%n %3\n%) %KImię i nazwisko%n: %5 %6\n%) %KNumer telefonu%n%W:%n %8\n%) %KAdres IP%n%W:%n %W%4%n\n%) %KGrupy%n%W:%n %W%9%n\n user_info_header %K%n %W%1%n/%2%n\n user_info_nickname %KPseudonim%n: %W%1%n \n user_info_name %KImię i nazwisko%n: %W%1 %2%n \n user_info_status %KStan%n: %W%1%n \n user_info_block %rBlokowan%@1%n \n user_info_ip %KAdres%n: %W%1%n \n user_info_offline %rNie widzi stanu%n \n user_info_not_in_contacts %RNie ma nas w swoich kontaktach\n user_info_firewalled %rZnajduje się za firewall/NAT\n user_info_mobile %KTelefon%n: %W%1%n \n user_info_groups %KGrupy%n: %W%1%n \n user_info_footer \n user_info_avail %Wdostępn%@1%n user_info_avail_descr %Wdostępn%@1%n %2 user_info_busy %wzajęt%@1%n user_info_busy_descr %wzajęt%@1%n %2 user_info_not_avail %Kniedostępn%@1%n user_info_not_avail_descr %Kniedostępn%@1%n %2 user_info_invisible %Cniewidoczn%@1%n user_info_invisible_descr %Cniewidoczn%@1%n %2 user_info_blocked %mblokując%@1%n user_info_unknown %Rnieznany%n group_members %) Grupa %W%1%n: %2\n group_member_already %! %W%1%n %Rnależy już do grupy %W%2%n\n group_member_not_yet %! %W%1%n %Rnie należy do grupy %W%2%n\n group_empty %! %RGrupa %n%W%1%n %Rjest pusta\n show_status_profile %) Profil: %W%1%n\n show_status_uin %) Numer: %W%1%n\n show_status_uin_nick %) Numer: %W%1%n (%W%2%n)\n show_status_status %) Aktualny stan: %W%1%2%n\n show_status_server %) Aktualny serwer: %W%1%n:%W%2%n\n show_status_avail %Wdostępny%n show_status_avail_descr %Wdostępny%n: %W%1%n show_status_busy %wzajęty%n show_status_busy_descr %wzajęty%n: %w%1%n show_status_invisible %Cniewidoczny%n show_status_invisible_descr %Cniewidoczny%n %C%1%n show_status_not_avail %Kniedostępny%n show_status_not_avail_descr %Kniedostępny%n: %K%1%n show_status_private_on , %Rtylko dla znajomych%n show_status_private_off show_status_connected_since %) Połączony od: %W%1%n\n show_status_disconnected_since %) Rozłączony od: %W%1%n\n show_status_last_conn_event %Y-%m-%d %H:%M show_status_last_conn_event_today %H:%M show_status_ekg_started_since %) Program działa od: %W%1%n \n show_status_ekg_started %Y-%m-%d %H:%M show_status_ekg_started_today %H:%M show_status_msg_queue %) Ilość wiadomości w kolejce do wysłania: %W%1%n \n aliases_list_empty %> Brak aliasów\n aliases_list %> %W%[10]1%n %b->%n %2\n aliases_list_next %b %n %2\n aliases_add %> Dodano alias %W%1%n %b->%n %W%2%n \n aliases_append %> Dodano do aliasu %W%1%n \n aliases_del %> Alias %W%1%n został usunięty\n aliases_del_all %> Wszystkie aliasy zostały usunięte\n aliases_exist %! %RAlias%n %W%1%n %Rjuż istnieje%n \n aliases_noexist %! %RAlias%n %W%1%n %Rnie istnieje%n \n aliases_command %! %W%1%n %Rjest wbudowaną komendą%n \n dcc_create_error %! %RNie można włączyć połączeń bezpośrednich: %1%n\n dcc_error_network %! %RBłąd transmisji z %1%n\n dcc_error_refused %! %RPołączenie z %1 zostało odrzucone%n\n dcc_error_unknown %! %RNieznany błąd połączenia bezpośredniego%n\n dcc_error_handshake %! %RNie można nawiązać połączenia z %1%n\n dcc_timeout %! %RPrzekroczono limit czasu operacji bezpośredniego połączenia%n\n dcc_not_supported %! %ROpcja %W%1%n nie jest jeszcze obsługiwana%n\n dcc_open_error %! %RNie można otworzyć %W%1%n: %2%n\n dcc_open_directory %! %RNie można otworzyć %W%1%n: Jest katalogiem%n\n dcc_show_pending_header %> Połączenia oczekujące:\n dcc_show_pending_send %) %W#%1%n, %2, wysyłanie %W%3%n\n dcc_show_pending_get %) %W#%1%n, %2, odbiór %W%3%n\n dcc_show_pending_voice %) %W#%1%n, %2, rozmowa%n\n dcc_show_active_header %> Połączenia aktywne:\n dcc_show_active_send %) %W#%1%n, %2, wysyłanie %W%3%n\n dcc_show_active_get %) %W#%1%n, %2, odbiór %W%3%n\n dcc_show_active_voice %) %W#%1%n, %2, rozmowa%n\n dcc_show_empty %! %RBrak bezpośrednich połączeń%n\n dcc_show_debug %> id=%1, type=%2, filename=%3, uin=%4, dcc=%5, offset=%6, size=%7 (%8%%)\n dcc_done_get %> Zakończono pobieranie pliku %W%2%n od %1\n dcc_done_send %> Zakończono wysyłanie pliku %W%2%n do %1\n dcc_get_offer %) %W%1%n przesyła plik %W%2%n o rozmiarze %W%3%n\n%) Wpisz %Wdcc get #%4%n by go odebrać, lub %Wdcc close #%4%n by anulować%n\n dcc_voice_offer %) %W%1%n chce rozmawiać\n%) Wpisz %Wdcc voice #%2%n by rozpocząć rozmowę, lub %Wdcc close #%2%n by anulować%n\n dcc_voice_unsupported %! %RNie wkompilowano obsługi rozmów głosowych. Przeczytaj %Wdocs/voip.txt%n\n dcc_voice_running %) %WMożna prowadzić tylko jedną rozmowę głosową na raz%n\n dcc_get_not_found %! %RNie znaleziono połączenia %W%1%n\n dcc_get_getting %) Rozpoczęto pobieranie pliku %W%2%n od %W%1%n\n dcc_get_cant_create %! %RNie można utworzyć pliku%n %W%1%n\n dcc_invalid_ip %! %RNieprawidłowy adres IP%n\n dcc_user_not_avail %! %R%1 musi być aktywn%@1, by móc wysłać plik%n\n query_started %r%#%n %) Rozpoczęto rozmowę z %W%1%n \n query_started_window %) Wciśnij %WAlt-G%n by ignorować, %WAlt-K%n by zamknąć okno\n query_finished %) Zakończono rozmowę z %W%1%n \n query_exist %! %RRozmowa z %W%1%n%R jest już prowadzona w okienku nr %W%2%n \n events_list_inactive %> %W%4%n, on %1 %2 %3 %K(nieaktywne)%n\n events_seq_incorrect %! %RNieprawidłowa sekwencja%n\n userlist_put_ok %) %WLista kontaktów została zapisana na serwerze%n\n userlist_put_error %! %RBłąd podczas zapisywania listy kontaktów%n\n userlist_get_ok %) %WListę kontaktów pobrano z serwera%n\n userlist_get_error %! %RBłąd podczas pobierania listy kontaktów%n\n userlist_clear_ok %) %WUsunięto listę kontaktów z serwera%n\n userlist_clear_error %! %RBłąd podczas usuwania listy kontaktów%n\n userlist_config_put_ok %) %WListę kontaktów i konfigurację zachowano na serwerze%n\n userlist_config_put_error %! %RBłąd podczas wysyłania listy kontaktów i konfiguracji%n\n userlist_config_get_ok %) %WListę kontaktów i konfigurację wczytano z serwera%n\n userlist_config_get_error %! %RBłąd podczas pobierania listy kontaktów i konfiguracji%n\n userlist_config_clear_ok %) %WUsunięto listę kontaktów i konfigurację z serwera%n\n userlist_config_clear_error %! %RBłąd podczas usuwania listy kontaktów i konfiguracji%n\n quick_list %)%1\n quick_list,speech lista kontaktów: quick_list_avail %W%1%n quick_list_avail,speech %1 jest dostępny, quick_list_busy %w%1%n quick_list_busy,speech %1 jest zajęty, quick_list_invisible %C%1%n window_add %) %WUtworzono nowe okno%n\n window_noexist %! %RWybrane okno nie istnieje%n\n window_no_windows %! %RNie można zamknąć ostatniego okna%n\n window_del %) Zamknięto okno\n windows_max %! %RWyczerpano limit ilości okien%n\n window_list_query %) %1: rozmowa z %W%2%n\n window_list_nothing %) %1: brak rozmowy\n window_list_floating %) %1: pływające %4x%5 w %2,%3 %W%6%n\n window_id_query_started %r%#%n %) Rozmowa z %W%2%n rozpoczęta w oknie %W%1%n\n window_kill_status %! %RNie można zamknąć okna statusowego%n\n bind_seq_incorrect %! Sekwencja %W%1%n jest nieprawidłowa\n bind_seq_add %) Dodano sekwencję %W%1%n\n bind_seq_remove %) Usunięto sekwencję %T%1%n\n bind_seq_list %) %1: %T%2%n\n bind_seq_exist %! Sekwencja %T%1%n ma już przypisaną akcję\n bind_seq_list_empty %! Brak przypisanych akcji\n at_list %> %1, %2, %3 %K(%4)%n\n at_added %> Utworzono plan %T%1%n\n at_deleted %> Usunięto plan %T%1%n\n at_deleted_all %> Usunięto plany użytkownika\n at_exist %! Plan %T%1%n już istnieje\n at_noexist %! Plan %T%1%n nie istnieje\n at_empty %! Brak planów\n at_timestamp %d-%m-%Y %H:%M at_back_to_past %! Gdyby można było cofnąć czas...\n timer_list %> %1, %2s, %3 %K(%4)%n %W%5%n\n timer_added %> Utworzono timer %W%1%n\n timer_deleted %> Usunięto timer %W%1%n\n timer_deleted_all %> Usunięto timery użytkownika\n timer_exist %! %RTimer%n %W%1%n %Rjuż istnieje%n \n timer_noexist %! %RTimer%N %W%1%n %Rnie istnieje%n \n timer_empty %! Brak timerów\n last_list_in %) %W <<%n %K[%1]%n %W%2%n %3\n last_list_out %) %w >>%n %K[%1]%n %2 %3\n last_list_empty %! Nie zalogowano żadnych wiadomości\n last_list_empty_nick %! Nie zalogowano żadnych wiadomości dla %T%1%n\n last_list_timestamp %d-%m-%Y %H:%M last_list_timestamp_today %H:%M last_clear_uin %) Wiadomości dla %T%1%n wyczyszczone\n last_clear %) Wszystkie wiadomości wyczyszczone\n queue_list_timestamp %d-%m-%Y %H:%M queue_list_message %) %W >>%n [%1] %2 %3\n queue_clear %) Kolejka wiadomości wyczyszczona\n queue_clear_uin %) Kolejka wiadomości wyczyszczona dla %T%1%n\n queue_wrong_use %! Komenda działa tylko przy braku połączenia z serwerem\n queue_empty %! Kolejka wiadomości jest pusta\n queue_empty_uin %! Brak wiadomości w kolejce dla %T%1%n\n queue_flush %) Wysłano zaległe wiadomości z kolejki\n conferences_list_empty %! Brak konferencji\n conferences_list %> %T%1%n: %2\n conferences_list_ignored %> %T%1%n: %2 (%yingorowana%n)\n conferences_add %> Utworzono konferencję %T%1%n\n conferences_not_added %) Nie utworzono konferencji %T%1%n\n conferences_del %> Usunięto konferencję %T%1%n\n conferences_del_all %> Usunięto wszystkie konferencje\n conferences_exist %! Konferencja %T%1%n już istnieje\n conferences_noexist %! Konferencja %T%1%n nie istnieje\n conferences_name_error %! Nazwa konferencji powinna zaczynać się od %T#%n\n conferences_rename %> Nazwa konferencji zmieniona: %T%1%n --> %T%2%n\n conferences_ignore %> Konferencja %T%1%n będzie ignorowana\n conferences_unignore %> Konferencja %T%1%n nie będzie ignorowana\n http_failed_resolving Nie znaleziono serwera http_failed_connecting Nie można połączyć się z serwerem http_failed_reading Serwer zerwał połączenie http_failed_writing Serwer zerwał połączenie http_failed_memory Brak pamięci key_generating %> Czekaj, generuję klucze...\n key_generating_success %> Wygenerowano i zapisano klucze\n key_generating_error %! Wystąpił błąd podczas generowania kluczy: %1\n key_private_exist %! Posiadasz już swoją parę kluczy\n key_public_deleted %> Klucz publiczny %1 został usunięty\n key_public_not_found %! Nie znaleziono klucza publicznego %1\n key_public_noexist %! Brak kluczy publicznych\n key_public_received %> Otrzymano klucz publiczny od %1\n key_public_write_failed %! Błąd podczas zapisu klucza publicznego: %1\n key_send_success %> Wysłano klucz publiczny do %1\n key_send_error %! Błąd podczas wysyłania klucza publicznego\n key_list %> %1 (%3)\n%) %2\n key_list_timestamp %Y-%m-%d %H:%M ekg-1.9~pre+r2855/themes/lcamtuf.theme000066400000000000000000000001751174410337000175660ustar00rootroot00000000000000# nieoficjalny theme. bazuje na wyglądzie windhoney.irc i paru sploitów # lcamtufa ;) prompt %B[%R+%B]%n error %B[%R!%B]%n ekg-1.9~pre+r2855/themes/leon.theme000066400000000000000000000235441174410337000170750ustar00rootroot00000000000000# EKG theme by Leszek 'Leon' Krupiński leszek@php.net # Based on 'Arim' theme ack_delivered %) %K dostarczono/%1 (%#)%n\n ack_queued %) %K dostarczono/%1 (%#) -czeka w kolejce-%n\n aliases_add %> %YDodano alias%n %W%1%n\n aliases_append %> %YDodano do aliasu%n %W%1%n %C->%n %W%2%n\n aliases_del %> %YAlias %W%1%n %Yzostał usunięty%n\n aliases_exist %! %RAlias %W%1%n %Rjuż istnieje%n\n aliases_invalid %! %RNiewłaściwy parametr%n %C(help alias ?)%n\n aliases_list_empty %> %YBrak aliasów%n\n aliases_list_next %> %[8]3 %K=>%n %g%2%n\n aliases_list %> %W%[10]1%n %C->%n %Y%2%n\n aliases_noexist %! %RAlias %W%1%n %Rnie istnieje%n\n already_connected %! %RJuż jesteś połączony%n\n already_searching %> %RPrzeszukiwanie w toku%n %YWpisz:%n %Wfind -stop%n %Yaby przerwać...%n\n auto_away %c%#%n %> %CPo%n %W%1%n %Crobię sobie przerwę%n\n auto_away_descr %c%#%n %> %CPo%n %W%1%n %Crobię sobie przerwę - %2%n\n autosaved %c%#%n%> %CAutomatyczny zapis konfiguracji%n away %c%#%n %> %CWracam za chwilę ... %n\n away_descr %c%#%n %> %CWracam za chwilę - %1%n\n back %c%#%n %> %GJestem z powrotem %n\n back_descr %c%#%n %> %GJestem z powrotem - %1%n\n change_failed %! %RBłąd podczas zmiany informacji w katalogu publicznym!%n\n change_not_enough_params %! %RPolecenie wymaga podania %Wwszystkich%n %Rparametrów!%n\n change_timeout %! %RPrzekroczono limit czasu operacji zmiany katalogu publicznego!%n\n change %> %YInformacje w katalogu publicznym zostaly zmienione.%n\n chat_footer %c`----- ---- --- -- -%n\n chat_header %> %W%1%n: %c(%#%2)%n \n chat_line %c|%n %1\n chat_line,irc %1\n chat_line_width 72 chat_timestamp [%H:%M] chat_timestamp_today [%H:%M] chat_timestamp_now conn_broken %! %c%#%n %W--/%n%r*%n%W/---%n %RPołączenie z serwerem przerwane\n connected %c%#%n %> [%G OK %n] %Y<-%n %GPołączono z serwerem\n connecting %> %YTrwa łączenie z serwerem...%n\n connected %c%#%n %> [%G OK %n] %W<-%n %GPołączono z serwerem%n\n connecting %> %WTrwa łączenie z serwerem...%n\n conn_failed %! %BBłąd podczas łączenia:%n %W%1%n\n conn_stopped %! %BŁączenie przerwane%n\n conn_timeout %! %BSerwer nie odpowiada%n\n disconnected %> %c%#%n %YRozłączono.%n\n disconnected_descr %> %c%#%n %YRozłączono - %1%n\n disconn_warning %! %BRozłączono nas.%n\n during_connect %! %YŁączenie w toku...%n %WProszę czekać%n \n ekg_version %) EKG - Eksperymentalny Klient Gadu-Gadu (%W%1%n)\n%)\n\n error_adding_ignored %! %RPodany wpis już istnieje%n\n error_adding %! %RBłąd podczas dodawania użytkownika%n\n error_deleting %! %RUżytkownika nie ma na liście%n\n error_loading_theme %c%#%n %! %RŁadowanie theme'a nie powiodło się%n\n error_not_ignored %! %RPodana osoba nie jest ignorowana%n\n error_reading_config %! %RBłąd podczas czytania pliku konfiguracyjnego%n\n error %R-!%n error_saving %!%RWystąpił bład podczas zapisu konfiguracji%n\n help_more %) %1\n help %> %[10]1 -> %Y%2%w %3\n ignored_added %> %YOd teraz ignorujesz%n %W%1%n\n ignored_deleted %> %YOd teraz przestajesz ignorować%n %W%1%n\n ignored_list_empty %> %YLista ignorów jest pusta%n\n ignored_list %> ig: %1\n invalid_uin %! %RNiewłaściwy numer%n %Yuin%n\n invisible %c%#%n %> %MJestem niewidzialny :)%n\n invisible_descr %c%#%n %> %MJestem niewidzialny :) - %1%n\n known_user %1 list_avail_descr %gAVA%n%n %W[%n%G+%n%W]%n %W%[18]1%n [%K%[,-15]3%n] [%[26]5]\n list_avail %gAVA%n%n %W[%n%G+%n%W]%n %W%[18]1%n [%K%[,-15]3%n]\n list_busy %cBUS%n%n %W[%n%C?%n%W]%n %Y%[18]1%n [%K%[,-15]3%n]\n list_busy_descr %cBUS%n%n %W[%n%C?%n%W]%n %Y%[18]1%n [%K%[,-15]3%n] [%[26]5]\n list_empty %> %YTwoja lista jest pusta%n\n list_invisible %mINV%n %W[ ]%n %m%[18]1%n [%K%[,-15]3%n]\n list_invisible_descr %mINV%n %W[ ]%n %m%[18]1%n [%K%[,-15]3%n] [%[26]5]\n list_not_avail %RN/A%n %W[%n%R-%n%W]%n %R%[18]1%n [%R...............%n]\n list_not_avail_descr %RN/A%n %W[%n%R-%n%W]%n %R%[18]1%n [%R...............%n] [%[26]5]\n message_footer %Y`----- ---- --- -- -%n\n message_header %> %1: %c(%Y%#%2%c)%n \n message_line_first,irc %c%3%n %G<%n%2%G>%n %1\n message_line,irc %1\n message_line %Y|%n %1\n message_line_width 72 message_line_width,irc 78 message_timestamp [%H:%M] message_timestamp_today [%H:%M] message_timestamp_now modify_done %> %YDane zmienione%n\n not_connected %! %RNie jesteś połączony z serwerem%n\n not_enough_params %! %RZa mało parametrów%n\n not_implemented %! %RTa funkcja nie została jeszcze zaimplementowana%n\n offline_mode %> %YJesteś w tybie off-line!%n\n passwd_failed %! %RBłąd podczas zmiany hasła!%n\n passwd_timeout %! %RPrzekroczono limit czasu operacji zmiany hasła!%n\n passwd %> %YHasło zostało zmienione.%n\n private_mode_invalid %! Nieprawidłowa wartość\n private_mode_is_off %> %w[%n%Ctylko dla przyjaciół%n%w]%n%Y:%n wyłączony\n private_mode_is_on %> %w[%n%Ctylko dla przyjaciół%n%w]%n%Y:%n włączony\n private_mode_off %> %w[%n%Ctylko dla przyjaciół%n%w]%n%Y:%n wyłączono\n private_mode_on %> %w[%n%Ctylko dla przyjaciół%n%w]%n%Y:%n włączono\n prompt2 %K *%n prompt %Y->%n quick_list_avail %g%1%n quick_list_busy %c%1%n quick_list %) %gobecny%W/%czajęty%W/%Mniewidzialny%n\n%)%1\n quick_list_invisible %M%1%n quit_descr %> %WDo zobaczenia.... - %1%n\n\n quit %> %WDo zobaczenia....%n\n\n readline_more --<-- ^[[1;37mnaciśnij [enter]^[[0m -->-- readline_prompt -> readline_prompt_away *> readline_prompt_away_win <* win.%1> readline_prompt_invisible ?> readline_prompt_invisible_win <. win.%1> readline_prompt_query %1> readline_prompt_query_win <%1/win.%2>-> readline_prompt_win <%% win.%1> registered_today %! %RJedna rejestracja na dzień wystarczy%n\n register_failed %! %RBłąd podczas rejestracji%n\n register_pending %! %RRejestracja w toku%n\n register_timeout %! %RPrzekroczono limit czasu operacji rejestrowania%n\n remind_failed %! %RBłąd podczas wysyłania hasła%n\n remind_timeout %! %RPrzekroczono limit czasu operacji wysłania hasła%n\n remind %> %YHasło zostało wysłane.%n\n saved %> %GZapisano !%n\n search_falied %! %RBłąd podczas przeszukiwania%n%Y:%n %W%1%n\n search_not_found %! %RNie znaleziono nikogo o takich danych%n\n search_results_multi_active %G+%n search_results_multi_busy %W<%c?%W>%n search_results_multi_female %MK%n search_results_multi_inactive %r!%n search_results_multi_male %BM%n search_results_multi_unknown %W?%n search_results_multi %W%7%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n search_results_single_active %G*%n search_results_single_busy %W<%c?%W>%n search_results_single_female %MK%n search_results_single_inactive %r!%n search_results_single_male %BM%n search_results_single_unknown %W?%n search_results_single %Y%7%n%W%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n search_stopped %) Szukanie zostało przerwane.\n search_timeout %! %RPrzekroczono limit czasu operacji szukania!%n\n sent_footer %M`----- ---- --- -- -%n\n sent_header %> Sent: %W%1%n %c(%M%#%2%c)%n\n sent_line_first,irc %c%3%n %G<%n%2%G>%n %1\n sent_line,irc %1\n sent_line %M|%n %1\n sent_line_width 72 sent_line_width,irc 78 sent_timestamp [%H:%M] sent_timestamp_today [%H:%M] sent_timestamp_now show_status_avail_descr %W[%n%G+%n%W]%n %Gdostępny: %1%n show_status_avail %W[%n%G+%n%W]%n %Gdostępny%n show_status_busy_descr %W[%n%C?%n%W]%n %Czajęty: %1%n show_status_busy %W[%n%C?%n%W]%n %Czajęty%n show_status_invisible_descr %W[%n%M*%n%W]%n %Mniewidoczny: %1%n show_status_invisible %W[%n%M*%n%W]%n %Mniewidoczny%n show_status_not_avail %W[%n%R-%n%W]%n %Rniedostępny%n show_status_private_off show_status_private_on %K[%n%Btylko dla przyjaciół%n%K]%n show_status %> %YTwój status: %n %W%1%n\n sms_chat EKG: %# chat %1: %2 sms_error %! %RBłąd podczas wysyłania sms'a%n\n sms_failed %! %RSms do%n %W%1%n %Rnie został dostarczony%n\n sms_msg EKG: %# msg %1: %2 sms_sent %> %GWysłano sms'a do%n %W%1%n\n sms_unknown %! %W%1%n %Rnie ma podanego numeru we wpisie%n\n status_avail %c%#%n %> %W%[18]1%n%W[%n%G+%n%W]%n %Gdostępn%@2%n\n status_avail_descr %c%#%n %> %W%[18]1%n%W[%n%G+%n%W]%n %Gdostępn%@2: %3%n\n status_busy %c%#%n %> %W%[18]1%n%W[%n%C?%n%W]%n %Czajęt%@2%n\n status_busy_descr %c%#%n %> %W%[18]1%n%W[%n%C?%n%W]%n %Czajęt%@2: %3%n\n status_invisible %c%#%n %> %W%[18]1%n%W[%n%C?%n%W]%n %mniewidoczn%@2%n\n status_invisible_descr %c%#%n %> %W%[18]1%n%W[%n%C?%n%W]%n %mniewidoczn%@2: %3%n\n status_not_avail %c%#%n %> %W%[18]1%n%W[%n%R-%n%W]%n %Rniedostępn%@2%n\n status_not_avail_descr %c%#%n %> %W%[18]1%n%W[%n%R-%n%W]%n %Rniedostępn%@2: %3%n\n sysmsg_footer %R+------------%n\n sysmsg_header %R+----------------%n Gadu-gadu system message %R----------------%n\n sysmsg_line %R|%n %1\n sysmsg_line_width 72 theme_default %c%#%n %> %YUstawiono domyślny wygląd%n\n theme_loaded %c%#%n\n%> %YWczytano temat graficzny.%n %K %n\n timestamp [%H:%M] unknown_command %! %RNieznane polecenie%n%Y:%n %W%0%1%n\n unknown_user %W[%n%Y%1%n%W]%n user_added %> %YUżytkownik %W%1%n %Yzostał dodany%n\n user_deleted %> %YUżytkownik%n %W%1%n %Yzostał usunięty%n\n user_exists %! %YUżytkownik%n %W%1%n %Yuz istnieje%n\n user_info_avail_descr %gdostępn%@1%n [%2] user_info_avail %gdostępn%@1%n user_info_busy %czajęt%@1%n user_info_busy_descr %czajęt%@1%n [%2] user_info_invisible %mniewidoczn%@1%n user_info_not_avail_descr %Rniedostępn%@1%n [%2] user_info_not_avail %Rniedostępn%@1%n user_info %) %YPseudonim%n%W:%n %W%1%n\n%) %YNumer%n%W:%n %W%2%n\n%) %YStan%n%W:%n %3\n%) %YAdres IP%n%W:%n %4\n%) %YImię i nazwisko%n%W: %5 %6%n\n%) %YAlias%n%W:%n %7\n%) %YNumer telefonu%n%W: %8%n\n%) %YGrupy%n%W:%n %9\n userlist_get_error %! %RBłąd podczas pobierania listy kontaktów!%n\n userlist_get_ok %) %YListę kontaktów wczytano z serwera.%n\n userlist_put_error %! %RBłąd podczas wysyłania listy kontaktów!%n\n userlist_put_ok %) %YListę kontaktów zachowano na serwerze.%n\n user_not_found %! %RNie ma na liście użytkownika %W%1%n!\n user_not_given %! %RMusisz podać użytkownika!%n\n user_not_given %! %RMusisz podać użytkownika%n\n variable %> %[,25]1%c%2%n\n variable_not_found %! %RNieznana zmienna%n%Y:%n %K[%n%W%1%n%K]%n\n ekg-1.9~pre+r2855/themes/matik.theme000066400000000000000000000033531174410337000172410ustar00rootroot00000000000000# Temacik dla EKG by [BFG]Matik # Email: matik@matikworld.net prompt %B== %n prompt2 %G ==%n saved %>%yZapisane%)%w\n quit %>%yBye!%)%w\n help %>%1%B%2 %> %w%3%w\n theme_loaded \n%>%GEKG%w theme by %W[%rBFG%W]%wMatik %B(matik@matikworld.net)%w\n\n connected %>%wPołączono %B(%w%#%B)%w\n\n known_user %w%[10]1%B[%w%[7]2%B] unknown_user %w%1 list_empty %>%wNarazie masz niewielu znajomych ;%rP%w\n list_avail %1%B[%Gdostepny %B] %w%3:%4%w\n list_avail_descr %1%B[%Gdostep:opis%B] %w%3:%4%w\n list_busy %1%B[%Yzajety %B] %w%3:%4%w\n list_busy_descr %1%B[%Yzajety:opis%B] %w%3:%4%w\n list_not_avail %1%B[%rniedostepny%B] %w%3:%4%w\n list_not_avail_descr %1%B[%rniedos:opis%B] %w%3:%4%w\n list_invisible %1%B[%Bniewidoczny%B] %w%3:%4%w\n away %>%wStatus%B: %Yzajety%w\n back %>%wStatus%B: %Gdostepny%w\n invisible %>%YStatus: %Bniewidoczny%w\n auto_away %>%BSpisz przy klawiaturze? Minęło %B%1 %wminut, przechodzę w tryb %yzajęty%w\n status_avail %G== %1 %wjest %Gdostepny %B(%w%#%B) %w\n status_avail_descr %G== %1 %wjest %Gdostepny: %w"%3" %B(%w%#%B) %w\n status_busy %Y== %1 %wjest %Yzajety %B(%w%#%B) %w\n status_busy_descr %Y== %1 %wjest %Yzajety: %w"%3" %B(%w%#%B) %w\n status_not_avail %R== %1 %wjest %Rniedostepny %B(%w%#%B) %w\n status_not_avail_descr %R== %1 %wjest %Rniedostepny: %w"%3" %B(%w%#%B) %w\n status_invisible %B== %1 %wjest %Bniewidoczny %B(%w%#%B) %w\n status_invisible_descr %B== %1 %wjest %Bniewidoczny: %w"%3" %B(%w%#%B) %w\n message_header %g+== %wOczekująca wiadomość od %1%g=== %B(%w%#%B)%g =---%w\n message_footer %g+=---%w\n chat_header %c+== %wWiadomość od %1%c=== %B(%w%#%B)%c =---%w\n chat_footer %c+=---%w\n ack_queued %>%1%wWiadomość dojdzie później %B(%w%#%B)%w\n ack_delivered %>%1%wWiadomość dotarła %B(%w%#%B)%w\n ekg-1.9~pre+r2855/themes/old.theme000066400000000000000000000353351174410337000167170ustar00rootroot00000000000000prompt %g-%G>%g-%n prompt2 %c-%C>%c-%n error %r-%R>%r-%n timestamp %H:%M readline_prompt % readline_prompt_away / readline_prompt_invisible . readline_prompt_query %1> readline_prompt_win %1%% readline_prompt_away_win %1/ readline_prompt_invisible_win %1. readline_prompt_query_win %2:%1> readline_prompt_win_act %1 (act/%2)%% readline_prompt_away_win_act %1 (act/%2)/ readline_prompt_invisible_win_act %1 (act/%2). readline_prompt_query_win_act %2:%1 (act/%3)> readline_more -- Wciśnij Enter by kontynuować lub Ctrl-D by przerwać -- known_user %T%1%n/%2 unknown_user %T%1%n none %1\n generic %> %1\n debug %n%1\n not_enough_params %! Za mało parametrów. Spróbuj %Thelp %1%n\n invalid_uin %! Nieprawidłowy numer użytkownika\n user_not_found %! Nie znaleziono użytkownika %T%1%n\n not_implemented %! Tej funkcji jeszcze nie ma\n unknown_command %! Nieznane polecenie: %T%1%n\n welcome %> %TEKG-%1%n (Eksperymentalny Klient Gadu-Gadu)\n%> Program jest rozprowadzany na zasadach licencji GPL w wersji 2\n%> %RPrzed użyciem przeczytaj ulotkę (polecenie ,,help'' lub F1)%n\n\n ekg_version %) EKG - Eksperymentalny Klient Gadu-Gadu (%T%1%n)\n%) libgadu-%1 (protokół %2, klient %3)\n group_empty %! Grupa %T%1%n jest pusta\n user_added %> Dopisano %T%1%n do listy kontaktów\n user_deleted %> Usunięto %T%1%n z listy kontaktów\n user_exists %! %T%1%n już istnieje w liście kontaktów\n error_adding %! Błąd podczas dopisywania do listy kontaktów\n error_deleting %! Błąd podczas usuwania z listy kontaktów\n away %> Zmieniono stan na zajęty %c(%C%#%c)%n\n away_descr %> Zmieniono stan na zajęty: %T%1%n%2 %c(%C%#%c)%n\n back %> Zmieniono stan na dostępny %c(%C%#%c)%n\n back_descr %> Zmieniono stan na dostępny: %T%1%n%2 %c(%C%#%c)%n\n invisible %> Zmieniono stan na niewidoczny %c(%C%#%c)%n\n invisible_descr %> Zmieniono stan na niewidoczny: %T%1%n%2 %c(%C%#%c)%n\n private_mode_is_on %> Tryb ,,tylko dla przyjaciół'' jest włączony\n private_mode_is_off %> Tryb ,,tylko dla przyjaciół'' jest wyłączony\n private_mode_on %> Włączono tryb ,,tylko dla przyjaciół''\n private_mode_off %> Wyłączono tryb ,,tylko dla przyjaciół''\n private_mode_invalid %! Nieprawidłowa wartość\n descr_too_long %! Długość opisu przekracza limit. Ilość uciętych znaków: %T%1%n\n help %> %1%2 - %3%4\n help_more %) %1\n help_alias %) %T%1%n jest aliasem i nie posiada opisu\n help_footer \n%> Gwiazdka (%T*%n) oznacza, że można uzyskać więcej szczegółów\n\n help_quick %> Przed użyciem przeczytaj ulotkę. Plik %Tdocs/ULOTKA%n zawiera krótki\n%> przewodnik po załączonej dokumentacji. Jeśli go nie masz, możesz\n%> ściągnąć pakiet ze strony %Thttp://ekg.chmurka.net/%n\n ignored_added %> Dodano %T%1%n do listy ignorowanych\n ignored_deleted %> Usunięto %1 z listy ignorowanych\n ignored_list %> %1\n ignored_list_empty %! Lista ignorowanych użytkowników jest pusta\n error_adding_ignored %! Błąd podczas dodawania do listy ignorowanych\n error_not_ignored %! %1 nie jest na liście ignorowanych\n list_empty %! Lista kontaktów jest pusta\n list_avail %> %1 %Y(dostępn%@2)%n %b%3:%4%n\n list_avail_descr %> %1 %Y(dostępn%@2: %n%5%Y)%n %b%3:%4%n\n list_busy %> %1 %G(zajęt%@2)%n %b%3:%4%n\n list_busy_descr %> %1 %G(zajęt%@2: %n%5%G)%n %b%3:%4%n\n list_not_avail %> %1 %r(niedostępn%@2)%n\n list_not_avail_descr %> %1 %r(niedostępn%@2: %n%5%r)%n\n list_invisible %> %1 %c(niewidoczn%@2)%n %b%3:%4%n\n list_unknown %> %1\n modify_done %> Zmieniono wpis w liście kontaktów\n quit %> Papa\n quit_descr %> Papa: %T%1%n%2\n config_changed Zapisać nową konfigurację? (tak/nie) saved %> Zapisano ustawienia\n error_saving %! Podczas zapisu ustawień wystąpił błąd\n message_header %g.-- %n%1 %c(%C%#%c/%2)%n %g--- -- -%n\n message_footer %g`----- ---- --- -- -%n\n message_line %g|%n %1\n message_line_width -8 message_timestamp %Y-%m-%d %H:%M chat_header %c.-- %n%1 %c(%C%#%c/%2)%n %c--- -- -%n\n chat_footer %c`----- ---- --- -- -%n\n chat_line %c|%n %1\n chat_line_width -8 chat_timestamp %Y-%m-%d %H:%M sent_header %b.-- %n%1 %c(%C%#%c)%n %b--- -- -%n\n sent_footer %b`----- ---- --- -- -%n\n sent_line %b|%n %1\n sent_line_width -8 sent_timestamp %Y-%m-%d %H:%M sysmsg_header %m.-- %TWiadomość systemowa %c(%C%#%c)%m --- -- -%n\n sysmsg_line %m|%n %1\n sysmsg_line_width -8 sysmsg_footer %m`----- ---- --- -- -%n\n ack_queued %> Wiadomość do %1 zostanie dostarczona później %c(%C%#%c)%n\n ack_delivered %> Wiadomość do %1 została dostarczona %c(%C%#%c)%n\n status_avail %> %1 jest dostępn%@2 %c(%C%#%c)%n\n status_avail_descr %> %1 jest dostępn%@2: %3 %c(%C%#%c)%n\n status_busy %> %1 jest zajęt%@2 %c(%C%#%c)%n\n status_busy_descr %> %1 jest zajęt%@2: %3 %c(%C%#%c)%n\n status_not_avail %> %1 jest niedostępn%@2 %c(%C%#%c)%n\n status_not_avail_descr %> %1 jest niedostępn%@2: %3 %c(%C%#%c)%n\n status_invisible %> %1 jest niewidoczn%@2 %c(%C%#%c)%n\n status_invisible_descr %> %1 jest niewidoczn%@2: %3 %c(%C%#%c)%n\n auto_away %> Automagicznie zmieniono stan na zajęty po %1 nieaktywności %c(%C%#%c)%n\n auto_away_descr %> Automagicznie zmieniono stan na zajęty po %1 nieaktywności %c(%C%#%c)%n: %T%2%n%3\n connecting %> Łączę się z serwerem...\n conn_failed %! Połączenie nie udało się: %1\n conn_failed_resolving Nie znaleziono serwera conn_failed_connecting Nie można połączyć się z serwerem conn_failed_invalid Nieprawidłowa odpowiedź serwera conn_failed_disconnected Serwer zerwał połączenie conn_failed_password Nieprawidłowe hasło conn_failed_404 Błąd serwera HTTP conn_failed_memory Brak pamięci conn_stopped %! Przerwano łączenie\n conn_timeout %! Przekroczono limit czasu operacji łączenia z serwerem\n connected %> Połączono %c(%C%#%c)%n\n disconnected %> Rozłączono %c(%C%#%c)%n\n disconnected_descr %> Rozłączono: %T%1%n%2 %c(%C%#%c)%n\n already_connected %! Klient jest już połączony. Wpisz %Treconnect%n aby połączyć ponownie\n during_connect %! Łączenie trwa. Wpisz %Tdisconnect%n aby przerwać\n conn_broken %! Serwer zerwał połączenie %c(%C%#%c)%n\n not_connected %! Brak połączenia z serwerem. Wpisz %Tconnect%n\n theme_loaded %> Wczytano opis wyglądu o nazwie %T%1%n\n theme_default %> Ustawiono domyślny opis wyglądu\n error_loading_theme %! Błąd podczas ładowania opisu wyglądu: %1\n variable %> %1 = %2\n variable_not_found %! Nieznana zmienna: %1\n variable_invalid %! Nieprawidłowa wartość zmiennej\n no_config %! Niekompletna konfiguracja. Wpisz:\n%! %Tset uin %n\n%! %Tset password %n\n%! %Tsave%n\n%! Następnie wydaj polecenie:\n%! %Tconnect%n\n%! Jeśli nie masz swojego numerka, wpisz:\n%! %Tregister %n\n\n error_reading_config %! Nie można odczytać pliku konfiguracyjnego: %1\n autosaved %> Automatycznie zapisano ustawienia\n register %> Rejestracja poprawna. Wygrany numerek: %T%1%n\n register_failed %! Błąd podczas rejestracji\n register_pending %! Rejestracja w toku\n register_timeout %! Przekroczono limit czasu operacji rejestrowania\n registered_today %! Już zarejestrowano jeden numer. Nie nadużywaj\n unregister %> Konto %T%1%n wykasowane.\n unregister_timeout %! Przekroczono limit czasu operacji usuwania konta\n unregister_bad_uin %! Nie poprawny UIN: %T%1%n\n unregister_failed %! Błąd podczas usuwania konta\n remind %> Hasło zostało wysłane\n remind_failed %! Błąd podczas wysyłania hasła\n remind_timeout %! Przekroczono limit czasu operacji wysłania hasła\n passwd %> Hasło zostało zmienione\n passwd_failed %! Błąd podczas zmiany hasła\n passwd_timeout %! Przekroczono limit czasu operacji zmiany hasła\n change_not_enough_params %! Polecenie wymaga podania %Twszystkich%n parametrów\n change %> Informacje w katalogu publicznym zostały zmienione\n change_failed %! Błąd podczas zmiany informacji w katalogu publicznym\n change_timeout %! Przekroczono limit czasu operacji zmiany katalogu publicznego\n sms_error %! Błąd wysyłania SMS\n sms_unknown %! %1 nie ma podanego numeru komórki\n sms_sent %> SMS do %T%1%n został wysłany\n sms_failed %! SMS do %T%1%n nie został wysłany\n sms_msg EKG: msg %1 %# >> %2 sms_chat EKG: chat %1 %# >> %2 search_failed %! Wystąpił błąd podczas szukania: %1\n search_timeout %! Przekroczono limit czasu operacji szukania\n search_not_found %! Nie znaleziono\n search_results_multi_active %G!%n search_results_multi_busy %g!%n search_results_multi_inactive search_results_multi_unknown - search_results_multi_female k search_results_multi_male m search_results_multi %7 %[-10]1%K|%n%[12]3%K|%n%6%K|%n%[20]2%K|%n%[4]5%K|%n%[16]4\n search_results_single_active %G(aktywn%@1)%n search_results_single_busy %g(zajęt%@1)%n search_results_single_inactive %r(nieaktywn%@1)%n search_results_single_unknown %T-%n search_results_single_female %Mkobieta%n search_results_single_male %Cmężczyzna%n search_results_single %) Nick: %T%3%n\n%) Numerek: %T%1%n\n%) Imię i nazwisko: %T%2%n\n%) Miejscowość: %T%4%n\n%) Rok urodzenia: %T%5%n\n%) Płeć: %6\n process %> %(-5)1 %2\n no_processes %! Nie ma działających procesów\n process_exit %> Proces %1 (%2) zakończył działanie z wynikiem %3\n exec %1\n",1); /* %1 treść, %2 pid */ exec_error %! Błąd uruchamiania procesu: %1\n user_info %) Pseudonim: %T%3%n\n%) Numer: %T%7%n\n%) Stan: %8\n%) Imię i nazwisko: %T%1 %2%n\n%) Alias: %T%4%n\n%) Numer telefonu: %T%5%n\n%) Grupy: %T%6%n\n user_info_avail %Ydostępn%@1%n user_info_avail_descr %Ydostępn%@1%n (%2) user_info_busy %Gzajęt%@1%n user_info_busy_descr %Gzajęt%@1%n (%2) user_info_not_avail %rniedostępn%@1%n user_info_not_avail_descr %rniedostępn%@1%n (%2) user_info_invisible %cniewidoczn%@1%n show_status_profile %) Profil: %T%1%n\n show_status_uin %) Numer: %T%1%n\n show_status_uin_nick %) Numer: %T%1%n (%T%2%n)\n show_status_status %) Aktualny stan: %T%1%2%n\n show_status_server %) Aktualny serwer: %T%1%n:%T%2%n\n show_status_avail %Ydostępny%n show_status_avail_descr %Ydostępny%n (%T%1%n%2) show_status_busy %Gzajęty%n show_status_busy_descr %Gzajęty%n (%T%1%n%2) show_status_invisible %bniewidoczny%n show_status_invisible_descr %bniewidoczny%n (%T%1%n%2) show_status_not_avail %rniedostępny%n show_status_private_on , tylko dla znajomych show_status_private_off aliases_invalid %! Nieprawidłowy parametr\n aliases_list_empty %! Brak aliasów\n aliases_list %> %T%1%n: %2\n aliases_list_next %> %3 %2\n aliases_add %> Utworzono alias %T%1%n\n aliases_append %> Dodano do aliasu %T%1%n\n aliases_del %) Usunięto alias %T%1%n\n aliases_exist %! Alias %T%1%n już istnieje\n aliases_noexist %! Alias %T%1%n nie istnieje\n aliases_command %! %T%1%n jest wbudowaną komendą\n dcc_create_error %! Nie można włączyć połączeń bezpośrednich: %1\n dcc_error_network %! Błąd transmisji z %1\n dcc_error_refused %! Połączenie z %1 zostało odrzucone\n dcc_error_unknown %! Nieznany błąd połączenia bezpośredniego\n dcc_error_handshake %! Nie można nawiązać połączenia z %1\n dcc_timeout %! Przekroczono limit czasu operacji bezpośredniego połączenia\n dcc_unknown_command %! Nieznana opcja: %T%1%n\n dcc_not_supported %! Opcja %T%1%n nie jest jeszcze obsługiwana\n dcc_open_error %! Nie można otworzyć %T%1%n: %2\n dcc_open_directory %! Nie można otworzyć %T%1%n: Jest katalogiem\n dcc_show_pending_header %> Połączenia oczekujące:\n dcc_show_pending_send %) #%1, %2, wysyłanie %T%3%n\n dcc_show_pending_get %) #%1, %2, odbiór %T%3%n\n dcc_show_pending_voice %) #%1, %2, rozmowa\n dcc_show_active_header %> Połączenia aktywne:\n dcc_show_active_send %) #%1, %2, wysyłanie %T%3%n\n dcc_show_active_get %) #%1, %2, odbiór %T%3%n\n dcc_show_active_voice %) #%1, %2, rozmowa\n dcc_show_empty %> Brak bezpośrednich połączeń\n dcc_show_debug %> id=%1, type=%2, filename=%3, uin=%4, dcc=%5\n dcc_done_get %> Zakończono pobieranie pliku %T%2%n od %1\n dcc_done_send %> Zakończono wysyłanie pliku %T%2%n do %1\n dcc_get_offer %) %1 przesyła plik %T%2%n o rozmiarze %T%3%n\n%) Wpisz %Tdcc get #%4%n by go odebrać, lub %Tdcc close #%4%n by anulować\n dcc_voice_offer %) %1 chce rozmawiać\n%) Wpisz %Tdcc voice #%2%n by rozpocząć rozmowę, lub %Tdcc close #%2%n by anulować\n dcc_voice_unsupported %) Nie wkompilowano obsługi rozmów głosowych. Przeczytaj %Tdocs/voip.txt%n\n dcc_voice_running %) Można prowadzić tylko jedną rozmowę głosową na raz\n dcc_get_not_found %! Nie znaleziono połączenia %T%1%n\n dcc_get_getting %) Rozpoczęto pobieranie pliku %T%2%n od %1\n dcc_get_cant_create %! Nie można utworzyć pliku %T%1%n\n dcc_invalid_ip %! Nieprawidłowy adres IP\n query_started %) Rozpoczęto rozmowę z %T%1%n\n query_finished %) Zakończono rozmowę z %T%1%n\n query_exist %! Rozmowa z %T%1%n jest już prowadzona w okienku nr %T%2%n\n events_act_toomany_params %! Za dużo parametrów\n events_seq_incorrect %! Nieprawidłowa sekwencja\n userlist_put_ok %) Listę kontaktów zachowano na serwerze\n userlist_put_error %! Błąd podczas wysyłania listy kontaktów\n userlist_get_ok %) Listę kontaktów wczytano z serwera\n userlist_get_error %! Błąd podczas pobierania listy kontaktów\n quick_list %)%1\n quick_list_avail %T%1%n quick_list_busy %w%1%n quick_list_invisible %K%1%n history_send > %y%2 [%3]:%n %4\n history_recv < %g%2 [%3]:%n %4\n history_error %! %1\n window_add %) Utworzono nowe okno\n window_noexist %! Wybrane okno nie istnieje\n window_no_windows %! Nie można zamknąć ostatniego okna\n window_del %) Zamknięto okno\n windows_max %! Wyczerpano limit ilości okien\n window_list_query %) %1: rozmowa z %T%2%n\n window_list_nothing %) %1: brak rozmowy\n window_invalid %! Nieprawidłowy parametr\n window_id_query_started %) Rozmowa z %T%2%n rozpoczęta w oknie %W%1%n\n window_kill_status %! Nie można zamknąć okna statusowego\n bind_seq_incorrect %! Sekwencja %T%1%n jest nieprawidłowa\n bind_seq_add %) Dodano sekwencję %T%1%n\n bind_seq_remove %) Usunięto sekwencję %T%1%n\n bind_invalid %! Nieprawidłowy parametr\n bind_seq_list %) %1: %T%2%n\n bind_seq_exist %! Sekwencja %T%1%n ma już przypisaną akcję\n bind_seq_list_empty %! Brak przypisanych akcji\n timer_list %> %1, %2s, %3\n last_list_in %) %Y <<%n [%1] %2 %3\n last_list_out %) %G >>%n [%1] %2 %3\n last_list_empty %! Nie zalogowano żadnych wiadomości.\n last_list_empty_nick %! Nie zalogowano żadnych wiadomości od %W%1%n.\n last_list_timestamp %m-%d-%Y %H:%M conferences_invalid %! Nieprawidłowy parametr\n conferences_list_empty %! Brak konferencji\n conferences_list %> %T%1%n: %2\n conferences_list_ignored %> %T%1%n: %2 (%yingorowana%n)\n conferences_add %> Utworzono konferencję %T%1%n\n conferences_not_added %) Nie utworzono konferencji %T%1%n\n conferences_del %> Usunięto konferencję %T%1%n\n conferences_exist %! Konferencja %T%1%n już istnieje\n conferences_noexist %! Konferencja %T%1%n nie istnieje\n conferences_name_error %! Nazwa konferencji powinna zaczynać się od %T#%n\n conferences_rename %> Nazwa konferencji zmieniona: %T%1%n --> %T%2%n\n conferences_ignore %> Konferencja %T%1%n będzie ignorowana\n conferences_unignore %> Konferencja %T%1%n nie będzie ignorowana\n http_failed_resolving Nie znaleziono serwera http_failed_connecting Nie można połączyć się z serwerem http_failed_reading Serwer zerwał połączenie http_failed_writing Serwer zerwał połączenie http_failed_memory Brak pamięci ekg-1.9~pre+r2855/themes/sic.theme000066400000000000000000000154001174410337000167060ustar00rootroot00000000000000# EKG theme by (sic!) wersja troche poprawiona # based on: wszystkie inne theme'y po trochu # a tak wogule to ciągle jakieś zmiany robie i ich końca nie widać #takietam propty ekg_version %) %cEKG%n - %CE%nksperymentalny %CK%nlient %CG%nadu-Gadu (%W%1%n)\n prompt %Y->%n prompt2 %K *%n error %R-!%n timestamp %H:%M welcome %cE%n%Wksperymentalny%n %K(C)2001|2002 Wojtek Kaniewski i inni%n \n %cK%n%Wlient%n %KProgram jest rozprowadzany na zasadach licencji GPL%n\n %cG%n%Wadu-Gadu%n %KPrzed użyciem przeczytaj ulotkę (polecenie 'help' lub F1)%n\n known_user %1 unknown_user %W[%n%Y%1%n%W]%n user_not_given %! %RMusisz podać użytkownika%n\n readline_prompt -> readline_prompt_away ?> readline_prompt_invisible *> readline_more [>] naciśnij ENTER not_enough_params %! %RZa mało parametrów%n\n #komunikaty unknown_command %! %RNieznane polecenie%n%Y:%n %W%0%1%n\n saved %> %GZapisano !%n\n error_saving %!%RWystąpił bład podczas zapisu konfiguracji%n\n error_reading_config %!%RWystąpił błąd odczytu pliku z konfiguracją%n\n quit %> %GP%n%Ca%n%Rp%n%Ba%n %W....%n\n\n help %> %[10]1 -> %Y%2%w %3\n help_more %) %c%1%n\n #header/footer message_header %C%1%n %K[%C%#%n|%c%2%n%K]%n\n message_footer message_line %1\n message_line_width 75 chat_header %W%1%n %W[%C%#%n|%c%2%n%W]%n\n chat_footer chat_line %1\n chat_line_width 75 sysmsg_header %R*%n %cGadu-Gadu: wiadomość systemowa%n %R*%n\n sysmsg_footer %R*%n %c --- %n %R*%n\n sysmsg_line %R|%n %1\n sysmsg_line_width 75 theme_loaded %c%#%n %> %Ytheme wczytany%n %R[%n%Wsic%n%R]%n %n\n theme_default %c%#%n %> %YUstawiono domyślny wygląd%n\n error_loading_theme %c%#%n %! %RŁadowanie theme'a nie powiodło się%n\n user_info %> %W%4%n / %3 (%1 %2) / %5\n modify_done %> %YDane zmienione%n\n search_results_single_active %G*%n search_results_single_inactive %r!%n search_results_single_female %MK%n search_results_single_male %BM%n search_results_single %Y%7%n%W%[-10]1%n %K|%n %[12]3 %K|%n %6 %K|%n %[20]2 %K|%n %[4]5 %K|%n %c%[16]4%n\n already_searching %> %RPrzeszukiwanie w toku%n %YWpisz:%n %Wfind -stop%n %Yaby przerwać...%n\n search_falied %! %RBłąd podczas przeszukiwania%n%Y:%n %W%1%n\n search_not_found %! %RNie znaleziono nikogo o takich danych%n\n #wyglad listy list_empty %> %YTwoja lista jest pusta%n\n list_avail %W[%n%G+%n%W]%n %W%[14]1%n [%K%[,-15]3%n] %K...%n\n list_avail_descr %W[%n%G+%n%W]%n %W%[14]1%n [%K%[,-15]3%n] %5\n list_busy %W[%n%C?%n%W]%n %c%[14]1%n [%K%[,-15]3%n] %K...%n\n list_busy_descr %W[%n%C?%n%W]%n %c%[14]1%n [%K%[,-15]3%n] %5\n list_not_avail %W[%n%R-%n%W]%n %K%[14]1%n [%K...............%n] %K...%n\n list_not_avail_descr %W[%n%R-%n%W]%n %K%[14]1%n [%K...............%n] %K%5%n\n list_invisible %K..%n%W[%n%M*%n%W]%n %K%[14]1%n [%K%[,-15]3%n]\n away %c%#%n %> %CAway%n%W:%n %Ywracam za chwilę%n %K... %n\n back %c%#%n %> %GJestem z powrotem %n\n away_descr %c%#%n %> %CAway%n%W:%n %Y%1%n\n invisible %c%#%n %> %MJestem niewidzialny :)%n\n auto_away %c%#%n %> %CPo%n %W%1%n %Crobię sobie przerwę%n\n #zmiana statusu / pm private_mode_is_on %> %YTryb%n %Ctylko dla przyjaciół%n %Yjest włączony%n\n private_mode_is_off %> %YTryb%n %Ctylko dla przyjaciół%n %Yjest wyłączony%n\n private_mode_on %> %YWłączono tryb%n %Ctylko dla przyjaciół%n\n private_mode_off %> %YWyłączono tryb%n %Ctylko dla przyjaciół%n\n private_mode_invalid %! %RZła wartość!%n %Cprawidłowa składnia to:%n %Yprivate%n %gon%n%W|%Koff%n\n status_avail %c%#%n %> %W%[14]1%n%W[%n%G+%n%W]%n %Gdostępn%@2%n \n status_avail_descr %c%#%n %> %W%[14]1%n%W[%n%G+%n%W]%n %G%3%n \n status_busy %c%#%n %> %W%[14]1%n%W[%n%C?%n%W]%n %czajęt%@2%n\n status_busy_descr %c%#%n %> %W%[14]1%n%W[%n%C?%n%W]%n %c%3%n\n status_not_avail %c%#%n %> %W%[14]1%n%W[%n%R-%n%W]%n %Kniedostępn%@2%n\n status_not_avail_descr %c%#%n %> %W%[14]1%n%W[%n%R-%n%W]%n %K%3%n\n status_invisible %c%#%n %> %W%[14]1%n%W[%n%C*%n%W]%n %Cniewidoczn%@2%3%n\n #e nie wiem do czego to jest #show_status %> %YTwój status: %n %W%1%n\n #show_status_avail %W[%n%G+%n%W]%n %Gdostępny%n #show_status_busy %W[%n%C?%n%W]%n %Czajęty%n #show_status_busy_descr %W[%n%C?%n%W]%n %C%1%n #show_status_invisible %W[%n%M*%n%W]%n %Mniewidoczny%n #show_status_not_avail %W[%n%R-%n%W]%n %Rniedostępny%n #show_status_not_avail_descr %W[%n%R-%n%W]%n %K%1%n ack_queued %) %K ack|%1 %K(%n%c%#%n%K)%n -dodano do kolejki-%n\n ack_delivered %) %K ack|%1 %K(%n%c%#%n%K) -dostarczono-%n\n sms_sent %> %GWysłano sms'a do%n %W%1%n\n sms_failed %! %RSms do%n %W%1%n %Rnie został dostarczony%n\n sms_error %! %RBłąd podczas wysyłania sms'a%n\n sms_unknown %! %W%1%n %Rnie ma ustawionego numeru%n\n variable %> %[,25]1%c%2%n\n variable_not_found %! %RNieznana zmienna%n%Y:%n %K[%n%W%1%n%K]%n\n variable_invalid %! %Wset%n %C%1%n%W:%n %2 %Rzła wartość.%n\n ignored_list %> ig: %1\n ignored_list_empty %> %YLista ignorów jest pusta%n\n ignored_added %> %YOd teraz ignorujesz%n %W%1%n\n ignored_deleted %> %YSkasowano%n %W%1%n %Yz listy ignorów%n\n invalid_uin %! %RNiewłaściwy numer%n %Yuin%n\n user_added %> %YUżytkownik %W%1%n %Yzostał dodany%n\n user_not_found %! %RNie ma na liście użytkownika %W%1%n\n user_deleted %> %YUżytkownik%n %W%1%n %Yzostał usunięty%n\n user_exists %! %YUżytkownik%n %W%1%n %Yjuż istnieje%n\n error_adding %! %RBłąd podczas dodawania użytkownika%n\n error_deleting %! %RUżytkownika nie ma na liście%n\n error_adding_ignored %! %RPodany wpis już istnieje%n\n error_not_ignored %! %RPodana osoba nie jest ignorowana%n\n conn_broken %! %c%#%n %W--/%n%r*%n%W/---%n %RPołączenie z serwerem przerwane%n\n connecting %> %YTrwa łączenie z serwerem...%n\n during_connect %! %YŁączenie w toku...%n %WProszę czekać%n \n connected %c%#%n %> %c[%n%G OK %n%c]%n %GPołączono z serwerem%n\n conn_falied %! %BBłąd podczas łączenia:%n %W%1%n\n disconnected %> %c%#%n %YRozłączono%n %W---< >---%n\n not_connected %! %RNie jesteś połączony z serwerem%n\n already_connected %! %RJuż jesteś połączony%n\n offline_mode %> %YJesteś w tybie off-line!%n\n error_reading_config %! %RBłąd podczas czytania pliku konfiguracyjnego%n\n no_config %! %RUwaga! Nieprawidłowa konfiguracja.%n %YZrób tak:%n %Wwpisz:%n\n%cset uin%n %Y%n\n%cset password%n %Y%n\n%csave%n\n%cconnect%n\n aliases_list %> %W%[10]1%n %C->%n %Y%2%n.\n aliases_add %> %YDodano alias%n %W%1%n %C->%n %W%2%n\n aliases_del %> %YAlias %W%1%n %Yzostał usunięty%n\n aliases_exist %! %RAlias %W%1%n %Rjuż istnieje%n\n aliases_noexist %! %RAlias %W%1%n %Rnie istnieje%n\n aliases_list_empty %> %YBrak aliasów%n\n aliases_invalid %! %RNiewłaściwy parametr%n %C(help alias ?)%n\n #lista userlist_put_ok %) %GLista kontaktów została zapisana na serwerze%n\n userlist_put_error %! %RBłąd podczas zapisywania listy kontaktów%n\n userlist_get_ok %) %GListę kontaktów pobrano z serwera%n\n userlist_get_error %! %RBłąd podczas pobierania listy kontaktów%n\n ekg-1.9~pre+r2855/themes/tohver.theme000066400000000000000000000040461174410337000174430ustar00rootroot00000000000000message_line_first %5%g(%w%3%g)%b-%B<%n%r%2%n%B>%n %1 message_line %1\n message_conference_line_first %5%g(%w%3%g)%b-%C<%n%B%2%n%C>%n %1 chat_line_first %5%g<%n%B%2%n%g>%n %1\n chat_conference_line_first %5%C<%n%B%2%n%C>%n %1\n chat_line %1\n sent_line_first %5%B<%n%g%2%n%B>%n %1\n sent_line %1\n secure %c(secure)-%n message_line_first,nc %5%g(%w%3%g)%b-%B<%n%r%2%n%B>%n %1 message_conference_line_first,nc %5%g(%w%3%g)%b-%C<%n%2%C>%n %1 message_line,nc %1\n chat_line_first,nc %5%g<%n%B%2%n%g>%n %1\n chat_conference_line_first,nc %5%C<%B%2%C>%n %1\n chat_line,nc %1\n sent_line_first,nc %5%B<%n%g%2%n%B>%n %1\n sent_line,nc %1\n known_user %1%n unknown_user %1%n message_timestamp_now %H:%M message_timestamp_today %H:%M message_timestamp %Y-%m-%d %H:%M list_avail %> %B%1 %Y(dostępn%@2)%n %b%3:%4%n\n list_avail_descr %> %B%1 %Y(dostępn%@2: %n%5%Y)%n %b%3:%4%n\n list_busy %> %B%1 %G(zajęt%@2)%n %b%3:%4%n\n list_busy_descr %> %B%1 %G(zajęt%@2: %n%5%G)%n %b%3:%4%n\n list_not_avail %> %B%1 %r(niedostępn%@2)%n\n list_not_avail_descr %> %B%1 %r(niedostępn%@2: %n%5%r)%n\n list_invisible %> %B%1 %c(niewidoczn%@2)%n %b%3:%4%n\n list_blocked %> %B%1 %m(blokując%@2)%n\n list_unknown", "%> %B%1\n ignored_deleted %) Usunięto %T%1 z listy ignorowanych\n ignored_exist %! %T%1 jest już na liście ignorowanych error_not_ignored %! %T%1 nie jest na liście ignorowanych blocked_deleted %) Usunięto %T%1 z listy blokowanych\n blocked_exist %! %T%1 jest już na liście blokowanych error_not_blocked %! %T%1 nie jest na liście blokowanych ack_queued %> Wiadomość do %T%1 zostanie dostarczona później ack_delivered %> Wiadomość do %T%1 została dostarczona status_avail %> %T%1 jest dostępn%@2\n status_avail_descr %> %T%1 jest dostępn%@2: %T%3%n\n status_busy %> %T%1 jest zajęt%@2\n status_busy_descr %> %T%1 jest zajęt%@2: %T%3%n\n status_not_avail %> %T%1 jest niedostępn%@2\n status_not_avail_descr %> %T%1 jest niedostępn%@2: %T%3%n\n status_invisible %> %T%1 jest niewidoczn%@2\n status_invisible_descr %> %T%1 jest niewidoczn%@2: %T%3%n\n ekg-1.9~pre+r2855/win32/000077500000000000000000000000001174410337000145615ustar00rootroot00000000000000ekg-1.9~pre+r2855/win32/README000066400000000000000000000005361174410337000154450ustar00rootroot00000000000000zbiór inkludów, które należy dodać do ścieżki przeszukiwania, by libgadu mogła się bez problemów skompilować za pomocą Borland C++ Buildera, bez konieczności posiadania środowiska GNU. wadą jest brak asynchronicznych połączeń, ale nie ma przeszkód, by je puścić w osobnym wątku. spora część kodu jest autorstwa Hao /* $Id$ */ ekg-1.9~pre+r2855/win32/arpa/000077500000000000000000000000001174410337000155045ustar00rootroot00000000000000ekg-1.9~pre+r2855/win32/arpa/inet.h000066400000000000000000000001171174410337000166130ustar00rootroot00000000000000/* * * * obsługa sieci. * * $Id$ */ #include ekg-1.9~pre+r2855/win32/config.h000066400000000000000000000001331174410337000161740ustar00rootroot00000000000000/* * * * zastępuje plik generowany przez skrypt ./configure. * * $Id$ */ ekg-1.9~pre+r2855/win32/netdb.h000066400000000000000000000001441174410337000160250ustar00rootroot00000000000000/* * * * inkludowany dla funkcji gethostbyname() * * $Id$ */ #include ekg-1.9~pre+r2855/win32/netinet/000077500000000000000000000000001174410337000162275ustar00rootroot00000000000000ekg-1.9~pre+r2855/win32/netinet/in.h000066400000000000000000000001201174410337000167770ustar00rootroot00000000000000/* * * * obsługa sieci. * * $Id$ */ #include ekg-1.9~pre+r2855/win32/pwd.h000066400000000000000000000002031174410337000155170ustar00rootroot00000000000000/* * * * nie mam pojęcia do czego potrzebny. widocznie jakaś architektura go * wymaga, więc zostawiam. * * $Id$ */ ekg-1.9~pre+r2855/win32/stdint.h000066400000000000000000000004741174410337000162440ustar00rootroot00000000000000/* * * * standardowe typy liczb całkowitych. zakładamy domyślne wartości dla * wszystkich kompilatorów win32. * * $Id$ */ #ifndef COMPAT_STDINT_H #define COMPAT_STDINT_H typedef unsigned long uint32_t; typedef unsigned short uint16_t; typedef unsigned char uint8_t; #endif /* COMPAT_STDINT_H */ ekg-1.9~pre+r2855/win32/sys/000077500000000000000000000000001174410337000153775ustar00rootroot00000000000000ekg-1.9~pre+r2855/win32/sys/ioctl.h000066400000000000000000000007731174410337000166710ustar00rootroot00000000000000/* * * * zastąpienie ioctl() przez ioctlsocket(). zwykły #define * to za mało ze względu na niezgodność typu ostatniego argumentu obu * funkcji. * * $Id$ */ #ifndef COMPAT_SYS_IOCTL_H #define COMPAT_SYS_IOCTL_H #include #include inline int ioctl(int fd, int request, ...) { va_list ap; unsigned long *foo; va_start(ap, request); foo = va_arg(ap, unsigned long*); va_end(ap); return ioctlsocket(fd, request, foo); } #endif /* COMPAT_SYS_IOCTL_H */ ekg-1.9~pre+r2855/win32/sys/socket.h000066400000000000000000000020471174410337000170430ustar00rootroot00000000000000/* * * * wrapper wielu funkcji i stałych niezbędnyc do obsługi socketów. * * $Id$ */ #ifndef COMPAT_SYS_SOCKET_H #define COMPAT_SYS_SOCKET_H #include #pragma link "Ws2_32.lib" /* W Borlandzie linkuje biblioteke z socketami */ #define ASSIGN_SOCKETS_TO_THREADS /* gg_connect bedzie zapisywal nr socketa na liscie, tak zeby mozna go bylo zamknac w polaczeniach synchronicznych (z innego watku) */ #define socket(af,type,protocol) WSASocket(af,type,protocol,0,0,WSA_FLAG_OVERLAPPED) #define write(handle,buf,len) send(handle,(const char*)buf,len,0) #define read(handle,buf,len) recv(handle,(const char*)buf,len,0) #ifdef ASSIGN_SOCKETS_TO_THREADS # define close(handle) gg_thread_close(-1,handle) #else # define close(handle) closesocket(handle) #endif #define EINPROGRESS WSAEINPROGRESS #define ENOTCONN WSAENOTCONN #define vsnprintf _vsnprintf #define snprintf _snprintf #define socket(x,y,z) static int fork() { return -1; } static int pipe(int filedes[]) { return -1; } #endif /* COMPAT_SYS_SOCKET_H */ ekg-1.9~pre+r2855/win32/sys/time.h000066400000000000000000000001001174410337000164750ustar00rootroot00000000000000/* * * * brakuje tego na win32. * * $Id$ */ ekg-1.9~pre+r2855/win32/sys/wait.h000066400000000000000000000005171174410337000165170ustar00rootroot00000000000000/* * * * funkcje wait() i waitpid() zwracają -1. tyle wystarczy, żeby skompilować * obsługę synchronicznych połączeń. * * $Id$ */ #ifndef COMPAT_SYS_WAIT_H #define COMPAT_SYS_WAIT_H static int wait(int *x) { return -1; }; static int waitpid(int x, int *y, int z) { return -1; } #endif /* COMPAT_SYS_WAIT_H */ ekg-1.9~pre+r2855/win32/unistd.h000066400000000000000000000002751174410337000162440ustar00rootroot00000000000000/* * * * na win32 widocznie nie ma strncasecmp(). * * $Id$ */ #ifndef COMPAT_UNISTD_H #define COMPAT_UNISTD_H #define strncasecmp strnicmp #endif /* COMPAT_UNISTD_H */