mercoledì, 23 aprile 2008
In Erlang we can use many method to access to lists and tuples, and some of them are very quick and easy.
With ++ and -- operators you can add and subtract lists, like in the following example:

Thelist=[1,2,3,4,5,6,7,8,9,10],
Even = lists:filter(fun(E) ->
       E rem 2 == 0
      end,
      Thelist),
Odd=Thelist -- Even,
Newlist = Odd ++ [ one, five ].

So Odd list will contains [1,3,5,7,9], Even list will contains [2,4,6,8,10] and Newlist will contain [1,3,5,7,9,one,five].
posted() stefko times() 10:20 | Permalink | commenti | commenti (popup)
list, erlang, arithmetic
lunedì, 07 aprile 2008
I've recently been involved in the problem of Flash (7.0 and following) XML socket.
Flash uses a "strange" kind of packet transfer in XML socket so Ejabberd 2.0.0 is not compatible with some Flash version.
I've seen a patch for Ejabberd 1.1.X versions and I've adapted it to fit with ejabberd 2.0.0.
Please note that this patch changes configure.ac file, but you must DO NOT run aclocal command.
At the moment aclocal.m4 file contains some macro that aclocal command will overwrite!
So please follow these steps to apply this patch to Ejabberd 2.0.0:

patch -p0 <flash-xml-ejabberd-2.0.0.diff
rm configure
autoconf
./configure --enable-flash-hack
make


And you'll be able to use XMPP like this:
<?xml version='1.0'?>
<flash:stream to='example.net' xmlns='jabber:client'
xmlns:flash='http://www.jabber.com/streams/flash' version='1.0'>
</flash:stream>
The patch is available here.
posted() stefko times() 13:03 | Permalink | commenti | commenti (popup)
flash, patch, ejabberd, xml socket
lunedì, 07 aprile 2008
As promised I'm releasing the cookie patch for ejabberd 2.0. The patch is quite simple and takes few minutes to check it out.
To apply the patch cumulatively, simply do the following

ejabberd/src/web/ $ patch < $HOME/ejabberd-2.0-cookie.patch
Otherwise you could apply the patch to single files:

ejabberd/src/web/ $ patch ejabberd_http.hrl $HOME/ejabberd_http_hrl.patch
ejabberd/src/web/ $ patch ejabberd_http.erl $HOME/ejabberd_http_erl.patch

Let me know if you got errors applying this patch.

Links:
ejabberd 2.0 Cumulative Cookie Patch
ejabberd_http Source Cookie Patch
ejabberd_http Header Cookie Patch
posted() loretoparisi times() 11:37 | Permalink | commenti | commenti (popup)
cookie, patch, ejabberd
venerdì, 04 aprile 2008
To add cookies to HTTP POST/GET requests in ejabberd (1.1.x and 2.x) we have to add some fields in the request headers, setting up the request and state records in ejabberd_http.erl module and its header file ejabberd_http.hrl.

First of all, we will add the field cookie to the record request in ejabberd_http.hrl header file as follows:

-record(request, {method,
                  path,
                  q = [],
                  us,
                  auth,
                  lang = "",
                  data = "",
                  cookie = "", %% lp: cookie request field
                  ip
                 }).


As you can see we are referring to ejabberd 2.0 (in the request record we have the new field ip for new user info).

Now we will edit the ejabberd_http.erl module, adding the field request_cookie to the record state:

-record(state, {sockmod,
                socket,
                request_method,
                request_version,
                request_path,
                request_auth,
                request_cookie, %% lp: cookie request field
                request_keepalive,
                (...)

 
At this point, we have to pass cookies to handlers, modifying the process_headers and process_request functions:

In the process_header, we will add to the case construct

process_header(State, Data) ->
    SockMod = State#state.sockmod,
    Socket = State#state.socket,
    case Data of
        {ok, {http_request, Method, Uri, Version}} ->
   
    (...)
        {ok, {http_header, _, 'Authorization', _, Auth}} ->
            State#state{request_auth = parse_auth(Auth)};
        {ok, {http_header, _, 'Cookie', _, Cookie}} ->
            %% lp: setting up request header cookie
            State#state{request_cookie = Cookie};
        {ok, {http_header, _, 'Content-Length', _, SLen}} ->
    (...)


In the process_request we have to modify the function header as follows:

process_request(#state{request_method = 'GET',
                       request_path = {abs_path, Path},
                       request_auth = Auth,
                       request_lang = Lang,
                       request_cookie = Cookie, %% lp: cookie request field
                       request_handlers = RequestHandlers,
                       sockmod = SockMod,
                       socket = Socket} = State) ->
                       
                        (...)
                        Request = #request{method = 'GET',
                               path = LPath,
                               q = LQuery,
                               auth = Auth,
                               lang = Lang,
                               cookie = Cookie, %% lp: here again :)
                               ip=IP},
                        (...)


and in the next header too:

process_request(#state{request_method = 'POST',
                       request_path = {abs_path, Path},
                       request_auth = Auth,
                       request_content_length = Len,
                       request_lang = Lang,
                       request_cookie = Cookie, %% lp: cookie
                       sockmod = SockMod,
                       socket = Socket,
                       request_handlers = RequestHandlers} = State)
  when is_integer(Len) ->

              (...)
              Request = #request{method = 'POST',
                               path = LPath,
                               q = LQuery,
                               auth = Auth,
                               cookie = Cookie, %% lp: cookie the last one ;)
                               data = Data,
                               lang = Lang},
              case process(RequestHandlers, Request) of
                 (...)


Now, we are ready to add the cookie request's field to our modules processing http requests:

process(#request{us = _US,
                     path = "login",
                     q = _Query,
                     lang = _Lang,
                     cookie = _Cookie} = Request) ->
          
              %% _Cookie will contain the request cookie now
              %% Manage request by cookies
              %% Send response :)



I will eventually post a addon patch for this :)

Enjoy your Jabber,
LP


PS. We used ejabberd 2.0, but you can do this in ejabberd 1.1.x in the same way


Links:
http://www.process-one.net/en/wiki/ejabberd_module_development/
posted() loretoparisi times() 18:05 | Permalink | commenti | commenti (popup)
cookie, request headers
martedì, 01 aprile 2008
In the previous post stefko told us about the new logging facility in ejabberd 2.0. But how can we apply logging verbosity levels in previous releases of ejabberd, such as ejabberd 1.1.2 ?
Well,
I modififed the ejabberd.hrl in this way:

%%
%%    --- 2007-05-10 - LP: LOGGER ---
%%     Verbosity levels:
%%
%%         Level 0 - No verbosity
%%         Level 1 - Error
%%         Level 2 - Warning
%%         Level 3 - Info
%%         Level 4 - Debug
%%

%% LP: Logger environment verbosity level variable
-define(LOGGER_ENV_LEVEL, "EJABBERD_LOGGER_LEVEL").

%% LP: Default Logger Level to 3 - Info level
-define(LOGGER_DEFAULTLEVEL, 3).%% LP: Get verbosity level

-define(LOGGER_SETLEVEL(Level),
    case string:to_integer(os:getenv(?LOGGER_ENV_LEVEL)) of
        {_,[]} ->
            case ({Level,[]} =< string:to_integer(os:getenv(?LOGGER_ENV_LEVEL))) of
                true -> Level;
                false -> string:to_integer(os:getenv(?LOGGER_ENV_LEVEL))
            end;   
        _ ->
            ?LOGGER_DEFAULTLEVEL
    end).

%% LP: Log messages
-define(LOGGER_LOG(Format, Args, Level),
    %% switch verbosity against level
    case Level of
           0 ->
            %% NO VERBOSITY
               ok;
        1 ->
            %% ERROR LEVEL
            error_logger:error_msg("ERROR(~p:~p:~p): "++Format++"~n",
                        [self(),?MODULE,?LINE]++Args);
           2 ->
            %% WARNING LEVEL
               error_logger:warning_msg("WARN(~p:~p:~p): "++Format++"~n",
                           [self(),?MODULE,?LINE]++Args);
          3 ->
              %% INFO_MSG LEVEL
              error_logger:info_msg("INFO(~p:~p:~p): "++Format++"~n",
                         [self(),?MODULE,?LINE]++Args);
          4 ->
              %% DEBUG LEVEL - no custom file logger
            error_logger:info_msg("DEBUG(~p:~p:~p) : "++Format++"~n",
                           [self(),?MODULE,?LINE]++Args);
          _ ->
             %% UNDEFINED LEVEL
              ok
       end).


Then redifining the ?DEBUG, ?INFO_MSG, ?WARNING_MSG and ?ERROR_MSG with the new ?LOGGER_LOG define and adjusting the logger level with ?LOGGER_SETLEVEL(Value), whereas Value goes from 0 (no messages) to 4 (debug mode) as follows:


%% LP: Debug Message
-define(DEBUG(Format, Args), ?LOGGER_LOG(Format, Args, ?LOGGER_SETLEVEL(4))).

%% LP: Info Message
-define(INFO_MSG(Format, Args), ?LOGGER_LOG(Format, Args, ?LOGGER_SETLEVEL(3))).

%% LP: Warning Message
-define(WARNING_MSG(Format, Args), ?LOGGER_LOG(Format, Args, ?LOGGER_SETLEVEL(2))).

%% LP: Error Message
-define(ERROR_MSG(Format, Args), ?LOGGER_LOG(Format, Args, ?LOGGER_SETLEVEL(1))).


In this way it's possible to log errors, warnings, messages using the same code (no need to change other modules log instructions) by setting up the environment variable "EJABBERD_LOGGER_LEVEL", called by os:getenv in the erl shell command:

erl ... -env ERL_MAX_PORTS 32000 \
        -env EJABBERD_LOGGER_LEVEL 4 \

LP

posted() loretoparisi times() 13:04 | Permalink | commenti | commenti (popup)
debug, loglevel, verbosity, logger
mercoledì, 26 marzo 2008
There's a very useful method to dynamically change verbosity level in ejabberd 2.0.0.
You must connect with a remote shell to the node you're interested to debug and simply write:

ejabberd_loglevel:set(LogLevel).

Where LogLevel is:
  • 0: No ejabberd log at all (not recommended)
  • 1: Critical
  • 2: Error
  • 3: Warning
  • 4: Info
  • 5: Debug
posted() stefko times() 11:46 | Permalink | commenti | commenti (popup)
debug, ejabberd, concurrent programming, loglevel
lunedì, 17 marzo 2008
In a previous post,  STDLIB: List To Record, we looked at a way to convert a list to a record by means of matching record fields. We made use of lists:mapfoldl and setelement lists and tuples's functions. That was just an exercise to practise with lists fun.
Now we'll a see a better way to implement this function that make more sense, using built-in function list_to_tuple and doing exactly the same job.

list_to_record(Query)->
   
    Fields=record_info(fields,qs),
    QS=#qs{},
       Record=lists:map(fun(Key) ->
        BKey=atom_to_list(Key),
          Vl=case catch lists:keysearch(BKey,1,Query) of
              {value,VKey} ->
                {K,V}=VKey,
                V;
             false ->  undefined;
             {'EXIT',Reason} -> undefined
             end
    end,Fields),
    list_to_tuple(lists:merge([qs],Record)).


That's all,
LP
posted() loretoparisi times() 10:13 | Permalink | commenti | commenti (popup)
record, list, erlang, stdlib, mapfoldl, tuple
venerdì, 14 marzo 2008
If you need to quickly make a cluster for many ejabberd nodes, you can find that a module that quickly initialize Mnesia tables can be very useful.
Follows the code of this module, really simple and autoexplicative.

-module(set_cluster_tables).

-export([
  setCopyTable/1
  ]).


loopTables(List, Dest, Node) ->

  lists:foreach(fun(Table) ->
    io:format("Change table copy for ~p in ~p\n",[Table,Dest]),
    mnesia:add_table_copy(Table, Node, Dest)
  end,List).

setCopyTable() ->
  io:format("Adding schema table\n",[]),
  mnesia:change_table_copy_type(schema, node(), disc_copies),
  TablesInRAM=[session,s2s,route,acl],
  TablesInDisc=[muc_registered,muc_room,motd,last_activity,roster,passwd,privacy
,offline_msg,disco_publish,vcard,private_storage,pubsub_node],

  loopTables(TablesInRAM,ram_copies,node()),
  loopTables(TablesInDisc,disc_only_copies,node()).

So calling set_cluster_tables:setCopyTable(). you will have all specified tables copied from "master" node. Remember to exit using q(). or init:stop() command, to cleanly exit from the shell.
posted() stefko times() 15:18 | Permalink | commenti (2) | commenti (2) (popup)
erlang, clustering, mnesia
mercoledì, 12 marzo 2008
In these days I'm using ejabberd 2.0.0, and I'm making a new module to set IM presences on Splinder site.
The
I've seen that the hook call c2s_update_presence in ejabberd_c2s module, is not using resource part of user's jid.
After a short discussion in the ejabberd developer chatroom, and after a little talk with badlop, we have decided to patch che ejabberd_c2s code.
I think it may be useful to use resource too, so I've patched session_established function, from:

PresenceEl = ejabberd_hooks:run_fold(
                                       c2s_update_presence,
                                       Server,
                                       NewEl,
                                       [User, Server]),

to:

PresenceEl = ejabberd_hooks:run_fold(
                                       c2s_update_presence,
                                       Server,
                                       NewEl,
                                       [User, Server, StateData#state.resource]),


So the code executing the hook can be independent from jid record but can use values inside this type of variable.
You can follow the story about this patch here.
posted() stefko times() 15:11 | Permalink | commenti (1) | commenti (1) (popup)

martedì, 04 marzo 2008
A new great piece of Erlang code has recently been released as stable.
There are many improvements in clustering architecture (now MUC is clustered too!), a complete rewrite of PubSub protocol and support for PEP, LDAP improvements, a better implementation HTTPBIND protocol and many many many other fixes and new features.

Official announce here

The future of IM is coming.
posted() stefko times() 11:27 | Permalink | commenti | commenti (popup)
pep , ejabberd, erlang, pubsub