<!--
   develbook.xml
-->

<chapter id="develbook">
   <title>
      EKG2 developer handbook 
   </title>
   <sect1 id="develbook-programming">
      <title>EKG2 developing</title>
      <sect2>
         <title>Tips for coders</title>
         <itemizedlist>
            <listitem>
               <para>
		  If you are fixing/adding something, keep style from rest of 
		  the code. Make indentations by tab characters, not space.
		  Make spaces after commas or semicolons. If you have other 
		  style, but your patches will be good and/or nessesary 
		  don't be suprise if Your code will be changed.
               </para>
            </listitem>
            <listitem>
               <para>
		  Add yourself to copyrights at the beginning of the file. 
		  If you don't do it I found that you relinquish your code.
		  Of course sended code must be on the same licence as the 
		  rest of the code. If not don't waste your time and don't 
		  send it to us.
               </para>
            </listitem>
            <listitem>
               <para>
		  Keep conventions. If all structure's variables have names
		  like <varname>foobar_count</varname>, don't add 
		  <varname>foocount</varname>, or <varname>nfoo</varname>.
               </para>
            </listitem>
            <listitem>
               <para>
		  Don't change api without reason. Even if you want to do it,
		  consult with other developers.
               </para>
            </listitem>
            <listitem>
               <para>
		  If you are making some bigger part of the code/module/file
		  designed to some function, try to call functions and vars
		  in way that can be understandable by other developers.
		  Example: function connected with list are beginning with
	   	  <function>list_*</function>, userlist functions 
		  <function>userlist_*</function>, configuration is something
		  like <function>config_*</function>.
               </para>
            </listitem>
            <listitem>
               <para>
		  For memory allocation use 
                  <function>xmalloc()</function>,
                  <function>xcalloc()</function>,
                  <function>xrealloc()</function> and
                  <function>xstrdup()</function>. You don't have to check
		  returned value. If there will be no memory, these functions
		  will handle soft program close. Look after freeing buffors, 
		  if they are not needed anymore.
               </para>
               <para>
                  Instead of <function>strncpy()</function> and
                  <function>strncat()</function> use
                  <function>strlcpy()</function> and
                  <function>strlcat()</function>, which takes as a parametr
		  full buffer size. You don't have to worry about how much 
		  memory is left, if zero character will go, etc. Both 
		  functions <emphasis>always</emphasis> return number of
		  characters, which were saved to the buffer.
               </para>
            </listitem>
            <listitem>
               <para>
		  If you don't know anything about memory allocation and 
		  string support in C, better find something else to do. Even
		  if code is correct, but it is disordered it will be refused.
               </para>
            </listitem>
            <listitem>
               <para>
                  Podsyłając patche, twórz je poleceniem <command>diff
                     -u</command>. 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.
               </para>
            </listitem>
            <listitem>
               <para>
                  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.
               </para>
            </listitem>
            <listitem>
               <para>
                  Poniższe linijki dopisane do ~/.vimrc ułatwiają wychwytywanie
                  znaków niedrukowalnych pozostawionych na końcach linii
                  poprzez zmianę ich koloru:
               </para>
               <programlisting>
<![CDATA[
    highlight WhitespaceEOL ctermbg=red guibg=red
    match WhitespaceEOL /\s\+$/
]]>
               </programlisting>
            </listitem>
            <listitem>
               <para>
                  Wszelkie komentarze powinny być w języku angielskim.
               </para>
            </listitem>
            <listitem>
               <para>
                  Wszystkie formatki i wszystko co zostaje wyświetlane na
                  ekranie ma być w języku angielskim.
               </para>
            </listitem>
            <listitem>
               <para>
                  Po zmianie jakiejkolwiek formatki należy w katalogu po/
                  wywołać make update-po i ewentualnie poprawić pliki *.po 
               </para>
            </listitem>
         </itemizedlist>
         <para>
	    Everyone can send patches, if they are respecting conventions.
	    It is about saving our project from disorder after one month.
	    Of course every change will be checked and if there is something
	    wrong author will be rebuked.
         </para>
      </sect2>
      <sect2>
         <title>API</title>
         <para>
            API documentation is avaiable on project homepage: <ulink
               url="http://www.ekg2.org/en/doxygen/">http://www.ekg2.org/en/doxygen/</ulink>
         </para>
      </sect2>
   </sect1>
   <sect1 id="develbook-files">
      <title>Formaty plików</title>
      <sect2>
         <title>Format listy kontaktów ekg2</title>
         <para>
            Lista kontaktów z pliku <filename>userlist</filename> jest tego samego
            formatu co eksportowana z windowsowego klienta:
         </para>
         <programlisting>
<![CDATA[
imię;nazwisko;pseudonim;wyświetlana_nazwa;telefon;grupy;opis;numer
]]>
         </programlisting>
         <para>
            ekg może dopisać użytkownika do kilku metagrup.
         </para>
         <itemizedlist>
            <listitem>
               <simpara>
                  __blocked - użytkownik blokowany
               </simpara>
            </listitem>
            <listitem>
               <simpara>
                  __offline - jesteśmy niedostępni dla użytkownika
               </simpara>
            </listitem>
            <listitem>
               <simpara>
                  __ignored_[poziom] - użytkownik jest ignorowany z danym poziomem
               </simpara>
            </listitem>
            <listitem>
               <simpara>
                  __ignored - wszystkie zdarzenia związane z użytkownikiem są ignorowane
               </simpara>
            </listitem>
         </itemizedlist>
      </sect2>
      <sect2>
         <title>Format konfiguracji ekg2</title>
         <para>
            Plik konfiguracyjny <filename>config</filename> zawiera kolejne
            wpisy w postaci:
         </para>
         <programlisting>
<![CDATA[
<set> <zmienna> <wartość>
bind <klawisz> <komenda>
bind-set <klawisz> <sekwencja>
alias <nazwa> <komenda>
on <zdarzenie> <priorytet> <założenia> <komenda>
at [nazwa] <czas>/<częstotliwość> <komenda>
timer [nazwa] [*/]<czas> <komenda>
plugin <nazwa>
]]>
         </programlisting>
         <para>
            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.
         </para>
         <para>
            Plik konfiguracyjny <filename>config-plugin</filename> zawiera
            kolejne wpisy w postaci:
         </para>
         <programlisting>
<![CDATA[
<zmienna> <wartość>
]]>
         </programlisting>
         <para>
            Plik konfiguracyjny ,,plugins'' zawiera kolejny wpisy w postaci:
         </para>
         <programlisting>
<![CDATA[
plugin <nazwa>
]]>
         </programlisting>
         <para>
            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.
         </para>
      </sect2>
      <sect2>
         <title>Format emotikon</title>
         <para>
            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 <literal>&lt;cmok&gt;</literal>może być
            zamieniona na <literal>:-*</literal> lub podobną, wedle uznania
            użytkownika.
         </para>
         <para>
            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 <filename>~/.gg/emoticons</filename>. Każda
            linia tego pliku definiuje jedno makro, a jej format jest
            Następujący:
         </para>
         <programlisting>
<![CDATA[
<makro><tabulatory><rozwiniecie>
]]>
         </programlisting>
         <para>
            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.
         </para>
         <para>
            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ć. 
         </para>
      </sect2>
      <sect2>
         <title>Format kolejki wiadomości</title>
         <para>
            Wiadomości są zapisywane w osobnych plikach w katalogu
            <filename>~/.gg/queue</filename>. Nazwa pliku jest połączeniem
            czasu wysłania wiadomości, kropki i kolejnej liczby, ale nie ma ona
            większego znaczenia. Chodzi o zachowanie kolejności przy sortowaniu
            plików. Pierwsza linia pliku zawiera wersję pliku. Aktualnie jest
            to ciąg znaków <literal>v1</literal>. Druga linia zawiera uid
            sesji, z której wiadomość była wysyłana. Trzecia linia zawiera
            listę odbiorców. Czwarta linia zawiera czas wysłania jako liczbę
            sekund od 1 stycznia 1970r. Piąta linia zawiera numer sekwencyjny
            lub dowolny ciąg znaków pozwalający jednoznacznie określić
            wiadomość. Kolejne linie są treścią wiadomości.
         </para>
      </sect2>
      <sect2>
         <title>Format pliku konfiguracji sesji ekg2</title>
         <para>
            Plik konfiguracyjny sessions-&lt;plugin&gt; może zawierać
            następujące definicje:
         </para>
         <programlisting>
<![CDATA[
	[uid sesji] - wszystkie zmienne będące poniżej są podrzędne dla 
		      tej sesji

	zmienna=wartość 
]]>
         </programlisting>
      </sect2>
   </sect1>
   <sect1 id="develbook-debugging">
      <title>Debugowanie</title>
      <para>
         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.
      </para>
      <screen>
<![CDATA[
$ gdb ekg ~/.ekg2/core.<pid>
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)
]]>
      </screen>
      <para>
         Od razu widzimy, że błąd wystąpił w funkcji
         <function>command_test_segv</function> z pliku
         <filename>commands.c</filename>. 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 <command>bt</command>,
         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.
      </para>
      <screen>
<![CDATA[
(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
]]>
      </screen>
      <para>
         Teraz widzimy, że po prostu użytkownik wywołał komendę
         <command>_segv</command>.  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.
      </para>
      <para>
         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.
      </para>
   </sect1>
   <sect1 id="develbook-themes">
      <title>Tworzenie tematów graficznych</title>
      <sect2>
         <title>Stworzenie nowego tematu</title>
         <para>
            Tworzenie własnego tematu graficznego do ekg2 najlepiej rozpocząc od
            wygenerowania "czystego" pliku z tematem, zawierającego ustawienia
            domyślne. Do wygenerowania takiego pliku można użyć prostego skryptu
            powłoki, na przykład takiego jak poniższy, który należy uruchomić w
            katalogu ze źródłami ekg2.
         </para>
         <programlisting role="shell">
<![CDATA[
grep -R -I 'format_add("' * | cut -d: -f2- | \
   perl -ne '/format_add\("(.*?)".+"(.*)".*/; print $1." ".$2."\n"' \
   > my.theme
   ]]>
         </programlisting>
         <para>
            Mając wygenerowany taki plik można przystąpić do modyfikacji.
            Wszystkie zmienione formatki należy zapisać, niezmienione można usunąć
            lub pozostawić. Następnie należy plik z tematem umieścić we właściwym
            katalogu - podkatalogu <filename>themes</filename> katalogu z danymi
            ekg2 (zazwyczaj <filename>/usr/share/ekg2</filename> lub
            <filename>/usr/local/share/ekg2</filename>) lub w katalogu z
            konfiguracją ekg2 (<filename>~/.ekg2</filename> lub
            <filename>~/etc/ekg2</filename>). Stworzony temat można przetestować
            ustawiając zmienną <varname>theme</varname>, nadając jej wartość taką
            jak nazwa pliku z tematem bez końcówki <literal>.theme</literal>.
         </para>
      </sect2>
      <sect2>
         <title>Formatki</title>
         <table frame="all">
            <title>Kolory w tematach graficznych</title>
            <tgroup cols="4">
               <colspec colname="kolor"/>
               <colspec colname="zwykly"/>
               <colspec colname="jasny"/>
               <colspec colname="tlo"/>
               <spanspec spanname="nocolor" namest="zwykly" nameend="tlo"/>
               <tbody>
                  <row>
                     <entry>
                        Kolor
                     </entry>
                     <entry>
                        Zwykły
                     </entry>
                     <entry>
                        Jasny
                     </entry>
                     <entry>
                        Tło
                     </entry>
                  </row>
                  <row>
                     <entry>
                        czarny/szary
                     </entry>
                     <entry>
                        %k
                     </entry>
                     <entry>
                        %K
                     </entry>
                     <entry>
                        %l
                     </entry>
                  </row>
                  <row>
                     <entry>
                        niebieski
                     </entry>
                     <entry>
                        %b
                     </entry>
                     <entry>
                        %B
                     </entry>
                     <entry>
                        %e
                     </entry>
                  </row>
                  <row>
                     <entry>
                        czerwony
                     </entry>
                     <entry>
                        %r
                     </entry>
                     <entry>
                        %R
                     </entry>
                     <entry>
                        %s
                     </entry>
                  </row>
                  <row>
                     <entry>
                        fioletowy
                     </entry>
                     <entry>
                        %m/%p
                     </entry>
                     <entry>
                        %M/%P
                     </entry>
                     <entry>
                        %q
                     </entry>
                  </row>
                  <row>
                     <entry>
                        turkusowy
                     </entry>
                     <entry>
                        %c
                     </entry>
                     <entry>
                        %C
                     </entry>
                     <entry>
                        %d
                     </entry>
                  </row>
                  <row>
                     <entry>
                        brązowy/żółty
                     </entry>
                     <entry>
                        %y
                     </entry>
                     <entry>
                        %Y
                     </entry>
                     <entry>
                        %z
                     </entry>
                  </row>
                  <row>
                     <entry>
                        zielony
                     </entry>
                     <entry>
                        %g
                     </entry>
                     <entry>
                        %G
                     </entry>
                     <entry>
                        %h
                     </entry>
                  </row>
                  <row>
                     <entry>
                        biały
                     </entry>
                     <entry>
                        %w
                     </entry>
                     <entry>
                        %W
                     </entry>
                     <entry>
                        %x
                     </entry>
                  </row>
                  <row>
                     <entry>
                        mrugający
                     </entry>
                     <entry>
                        %i
                     </entry>
                     <entry>
                        -
                     </entry>
                     <entry>
                        -
                     </entry>
                  </row>
                  <row>
                     <entry>
                        tłusty
                     </entry>
                     <entry>
                        %T
                     </entry>
                     <entry>
                        -
                     </entry>
                     <entry>
                        -
                     </entry>
                  </row>
                  <row>
                     <entry>
                        bez koloru
                     </entry>
                     <entry spanname="nocolor">
                        %n
                     </entry>
                  </row>
               </tbody>
            </tgroup>
         </table>
      </sect2>
      <sect2>
         <title>Dopełnianie do szerokości</title>
         <para>
            Przy parametrach %1-%9 można kazać dopełniać do konkretnej
            szerokości. przydaje się do wszelkiego rodzaju tabelek.
         </para>
         <table frame="all">
            <title>Dopełnianie do szerokości</title>
            <tgroup cols="2">
               <colspec name="typ"/>
               <colspec name="opis"/>
               <tbody>
                  <row>
                     <entry>
                        %[10]1
                     </entry>
                     <entry>
                        dopełnia spacjami z prawej pierwszy parametr do 10 pól
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %[-10]1
                     </entry>
                     <entry>
                        j.w. tylko że do lewej
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %[.5]1
                     </entry>
                     <entry>
                        dopełnia zerami
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %[,9]2
                     </entry>
                     <entry>
                        dopełnia kropkami
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %[_4]1
                     </entry>
                     <entry>
                        dopełnia znakami podkreślenia
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %(10)1
                     </entry>
                     <entry>
                        jeśli rozmiar parametru przekroczy 10 znaków nie obcina
                     </entry>
                  </row>
               </tbody>
            </tgroup>
         </table>
         <para>
            UWAGA! kolorkowe sekwencje ansi traktuje jak znaki, więc nie
            powinno się ich używać przy dopełnianiu parametrów.
         </para>
      </sect2>
      <sect2>
         <title>Końcówki zależne od płci</title>
         <para>
            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: <literal>%> %1 jest
               dostępn%@1</literal>
         </para>
         <para>
            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.
         </para>
      </sect2>
      <sect2>
         <title>Znaki zachęty</title>
         <table frame="all">
            <title>Znaki zachęty</title>
            <tgroup cols="2">
               <colspec name="typ"/>
               <colspec name="opis"/>
               <tbody>
                  <row>
                     <entry>
                        %>
                     </entry>
                     <entry>
                        prompt (domyślnie zielony)
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %!
                     </entry>
                     <entry>
                        error (domyślnie czerwony)
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %)
                     </entry>
                     <entry>
                        prompt2 (domyślnie turkusowy)
                     </entry>
                  </row>
                  <row>
                     <entry>
                        %#
                     </entry>
                     <entry>
                        timestamp (domyślnie GG:MM)
                     </entry>
                  </row>
               </tbody>
            </tgroup>
         </table>
         <para>
            <literal>%|</literal> oznacza koniec promptu. Jeśli ten format
            występuje, to przy przenoszeniu do następnej linii, tekst przed tym
            formatem zostanie wyświetlony ponownie.
         </para>
         <example>
            <title>Użycie formatu %|</title>
            <programlisting>
<![CDATA[
%> Długa linia, która zostanie podzielona na kilka linii
]]>
            </programlisting>
            <para>
               Na małym terminalu powyższy przykład wyświetli:
            </para>
            <screen>
<![CDATA[
	.-------------------------.
        | ::: Długa linia, która  |
        | zostanie podzielona na  |
        | kilka linii             |
	`-------------------------'
]]>
            </screen>
            <para>
               Po dodaniu %|, to znaczy:
            </para>
            <programlisting>
<![CDATA[
%> %|Długa linia, która zostanie podzielona na kilka linii
]]>
            </programlisting>
            <para>
               zostanie wyświetlone jako:
            </para>
            <screen>
<![CDATA[
        .-------------------------.
        | ::: Długa linia, która  |
	| ::: zostanie podzielona |
	| ::: na kilka linii      |
	`-------------------------'
]]>
            </screen>
         </example>
      </sect2>
      <sect2>
         <title>Użytkownicy spoza listy kontaktów</title>
         <para>
            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.
         </para>
      </sect2>
      <sect2>
         <title>Prompty readline</title>
         <para>
            Wpisy readline_*, oprócz readline_prompt_query nie mogą zawierać
            żadnych ,,procentowych'' kodów sterujących. Podobnie jest z
            promptem config_changed.
         </para>
      </sect2>
      <sect2>
         <title>Marginesy</title>
         <para>
            (ncurses) W ekg2 można ustawiać tzw. marginesy poprzez zmienną
            ncurses:margin_size. Aby z nich korzystać należy w formatce użyć
            znaków /| do oddzielenia tekstu znajdującego się po prawej i po
            lewej stronie.
         </para>
         <example>
            <title>Przykład użycia marginesów</title>
            <programlisting>
<![CDATA[
tekst/|tekst2
]]>
            </programlisting>
            <para>
               Powyższa formatka zostanie wyświetlona jako:
            </para>
            <screen>
<![CDATA[
tekst        tekst2
]]>
            </screen>
            <para>
               Odstęp reguluje się poprzez zmienną ncurses:margin_size.
            </para>
         </example>
      </sect2>
   </sect1>
   <sect1 id="develbook-plugins">
      <title>Tworzenie pluginów</title>
      <sect2>
         <title>Struktura plugin_t</title>
      </sect2>
      <sect2>
         <title>Obsługa zdarzeń</title>
      </sect2>
      <sect2>
         <title>Wywoływanie poleceń ekg2</title>
      </sect2>
      <sect2>
         <title>Wyświetlanie danych</title>
      </sect2>
   </sect1>
</chapter>
<!--
   vim: filetype=docbk encoding=iso-8859-2
-->
