*** empty log message ***

SVN Revision: 20
This commit is contained in:
Alexey Shchepin 2002-12-20 20:42:08 +00:00
parent 0e363bf8cb
commit ae30798efd
11 changed files with 632 additions and 101 deletions

271
sha_erl.c Normal file
View File

@ -0,0 +1,271 @@
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is SHA 180-1 Reference Implementation (Compact version)
*
* The Initial Developer of the Original Code is Paul Kocher of
* Cryptography Research. Portions created by Paul Kocher are
* Copyright (C) 1995-9 by Cryptography Research, Inc. All
* Rights Reserved.
*
* Contributor(s):
*
*/
#include <stdio.h>
#include <erl_driver.h>
#include <ei.h>
typedef struct {
ErlDrvPort port;
} sha_data;
typedef struct {
unsigned long H[5];
unsigned long W[80];
int lenW;
unsigned long sizeHi,sizeLo;
} j_SHA_CTX;
static void shaHashBlock(j_SHA_CTX *ctx);
void shaInit(j_SHA_CTX *ctx) {
int i;
ctx->lenW = 0;
ctx->sizeHi = ctx->sizeLo = 0;
/* Initialize H with the magic constants (see FIPS180 for constants)
*/
ctx->H[0] = 0x67452301L;
ctx->H[1] = 0xefcdab89L;
ctx->H[2] = 0x98badcfeL;
ctx->H[3] = 0x10325476L;
ctx->H[4] = 0xc3d2e1f0L;
for (i = 0; i < 80; i++)
ctx->W[i] = 0;
}
void shaUpdate(j_SHA_CTX *ctx, unsigned char *dataIn, int len) {
int i;
/* Read the data into W and process blocks as they get full
*/
for (i = 0; i < len; i++) {
ctx->W[ctx->lenW / 4] <<= 8;
ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i];
if ((++ctx->lenW) % 64 == 0) {
shaHashBlock(ctx);
ctx->lenW = 0;
}
ctx->sizeLo += 8;
ctx->sizeHi += (ctx->sizeLo < 8);
}
}
void shaFinal(j_SHA_CTX *ctx, unsigned char hashout[20]) {
unsigned char pad0x80 = 0x80;
unsigned char pad0x00 = 0x00;
unsigned char padlen[8];
int i;
/* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
*/
padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
shaUpdate(ctx, &pad0x80, 1);
while (ctx->lenW != 56)
shaUpdate(ctx, &pad0x00, 1);
shaUpdate(ctx, padlen, 8);
/* Output hash
*/
for (i = 0; i < 20; i++) {
hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
ctx->H[i / 4] <<= 8;
}
/*
* Re-initialize the context (also zeroizes contents)
*/
shaInit(ctx);
}
void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) {
j_SHA_CTX ctx;
shaInit(&ctx);
shaUpdate(&ctx, dataIn, len);
shaFinal(&ctx, hashout);
}
#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
static void shaHashBlock(j_SHA_CTX *ctx) {
int t;
unsigned long A,B,C,D,E,TEMP;
for (t = 16; t <= 79; t++)
ctx->W[t] =
SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
A = ctx->H[0];
B = ctx->H[1];
C = ctx->H[2];
D = ctx->H[3];
E = ctx->H[4];
for (t = 0; t <= 19; t++) {
TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL;
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
}
for (t = 20; t <= 39; t++) {
TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL;
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
}
for (t = 40; t <= 59; t++) {
TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL;
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
}
for (t = 60; t <= 79; t++) {
TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL;
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
}
ctx->H[0] += A;
ctx->H[1] += B;
ctx->H[2] += C;
ctx->H[3] += D;
ctx->H[4] += E;
}
/*----------------------------------------------------------------------------
*
* This code added by Thomas "temas" Muldowney for Jabber compatability
*
*---------------------------------------------------------------------------*/
char *shahash(char *str)
{
static char final[41];
char *pos;
unsigned char hashval[20];
int x;
if(!str || strlen(str) == 0)
return NULL;
shaBlock((unsigned char *)str, strlen(str), hashval);
pos = final;
for(x=0;x<20;x++)
{
snprintf(pos, 3, "%02x", hashval[x]);
pos += 2;
}
return (char *)final;
}
void shahash_r(const char* str, char hashbuf[41])
{
int x;
char *pos;
unsigned char hashval[20];
if(!str || strlen(str) == 0)
return;
shaBlock((unsigned char *)str, strlen(str), hashval);
pos = hashbuf;
for(x=0;x<20;x++)
{
snprintf(pos, 3, "%02x", hashval[x]);
pos += 2;
}
return;
}
static ErlDrvData sha_erl_start(ErlDrvPort port, char *buff)
{
sha_data* d = (sha_data*)driver_alloc(sizeof(sha_data));
d->port = port;
return (ErlDrvData)d;
}
static void sha_erl_stop(ErlDrvData handle)
{
driver_free((char*)handle);
}
static void sha_erl_output(ErlDrvData handle, char *buff, int bufflen)
{
sha_data* d = (sha_data*)handle;
ei_x_buff buf;
static char final[41];
char *pos;
unsigned char hashval[20];
int x;
if(bufflen == 0)
final[0] = '\000';
else
{
shaBlock(buff, bufflen, hashval);
pos = final;
for(x=0;x<20;x++)
{
snprintf(pos, 3, "%02x", hashval[x]);
pos += 2;
}
}
ei_x_new_with_version(&buf);
ei_x_encode_string(&buf, final);
driver_output(d->port, buf.buff, buf.index);
ei_x_free(&buf);
}
ErlDrvEntry sha_driver_entry = {
NULL, /* F_PTR init, N/A */
sha_erl_start, /* L_PTR start, called when port is opened */
sha_erl_stop, /* F_PTR stop, called when port is closed */
sha_erl_output, /* F_PTR output, called when erlang has sent */
NULL, /* F_PTR ready_input, called when input descriptor ready */
NULL, /* F_PTR ready_output, called when output descriptor ready */
"sha_erl", /* char *driver_name, the argument to open_port */
NULL, /* F_PTR finish, called when unloaded */
NULL, /* F_PTR control, port_command callback */
NULL, /* F_PTR timeout, reserved */
NULL /* F_PTR outputv, reserved */
};
DRIVER_INIT(sha_erl) /* must match name in driver_entry */
{
return &sha_driver_entry;
}

View File

@ -5,14 +5,16 @@ INCLUDES = -I/usr/lib/erlang/usr/include \
LIBDIRS = -L/usr/lib/erlang/lib/erl_interface-3.3.0/lib LIBDIRS = -L/usr/lib/erlang/lib/erl_interface-3.3.0/lib
all: expat_erl.so ERLSHLIBS = expat_erl.so sha_erl.so
all: $(ERLSHLIBS)
erl -make erl -make
expat_erl.so: expat_erl.c $(ERLSHLIBS): %.so: %.c
gcc -Wall $(INCLUDES) $(LIBDIRS) \ gcc -Wall $(INCLUDES) $(LIBDIRS) \
-lexpat \ -lexpat \
expat_erl.c \ $(subst .so,.c,$@) \
-lerl_interface \ -lerl_interface \
-lei \ -lei \
-o expat_erl.so -fpic -shared \ -o $@ -fpic -shared \

View File

@ -21,6 +21,7 @@ init() ->
ok = erl_ddll:load_driver(".", expat_erl), ok = erl_ddll:load_driver(".", expat_erl),
Port = open_port({spawn, expat_erl}, [binary]), Port = open_port({spawn, expat_erl}, [binary]),
db_init(), db_init(),
sha:start(),
ejabberd_auth:start(), ejabberd_auth:start(),
ejabberd_router:start(), ejabberd_router:start(),
ejabberd_sm:start(), ejabberd_sm:start(),

View File

@ -19,6 +19,7 @@
-export([start/0, start_link/0, -export([start/0, start_link/0,
set_password/2, set_password/2,
check_password/2, check_password/2,
check_password/4,
try_register/2]). try_register/2]).
%% gen_server callbacks %% gen_server callbacks
@ -110,6 +111,31 @@ check_password(User, Password) ->
false false
end. end.
check_password(User, Password, StreamID, Digest) ->
LUser = jlib:tolower(User),
F = fun() ->
case mnesia:read({passwd, LUser}) of
[E] ->
E#passwd.password
end
end,
case mnesia:transaction(F) of
{atomic, Passwd} ->
DigRes = if
Digest /= "" ->
Digest == sha:sha(StreamID ++ Passwd);
true ->
false
end,
if DigRes ->
true;
true ->
Passwd == Password
end;
_ ->
false
end.
set_password(User, Password) -> set_password(User, Password) ->
LUser = jlib:tolower(User), LUser = jlib:tolower(User),

View File

@ -113,9 +113,9 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
{auth, ID, {U, P, D, R}} -> {auth, ID, {U, P, D, R}} ->
io:format("AUTH: ~p~n", [{U, P, D, R}]), io:format("AUTH: ~p~n", [{U, P, D, R}]),
% TODO: digested password % TODO: digested password
case ejabberd_auth:check_password(U, P) of case ejabberd_auth:check_password(U, P,
StateData#state.streamid, D) of
true -> true ->
% TODO
ejabberd_sm:open_session(U, R), ejabberd_sm:open_session(U, R),
Res = jlib:make_result_iq_reply(El), Res = jlib:make_result_iq_reply(El),
send_element(StateData#state.sender, Res), send_element(StateData#state.sender, Res),
@ -181,7 +181,9 @@ session_established({xmlstreamelement, El}, StateData) ->
[FromJID, El, StateData]), [FromJID, El, StateData]),
presence_update(FromJID, El, StateData); presence_update(FromJID, El, StateData);
_ -> _ ->
ejabberd_router:route(FromJID, ToJID, El), ejabberd_router:route({StateData#state.user,
Server, ""},
ToJID, El),
presence_track(FromJID, ToJID, El, StateData) presence_track(FromJID, ToJID, El, StateData)
end; end;
_ -> _ ->
@ -267,24 +269,12 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
Attrs1 = lists:keydelete("type", 1, Attrs), Attrs1 = lists:keydelete("type", 1, Attrs),
{true, [{"type", "unavailable"} | Attrs1], StateData}; {true, [{"type", "unavailable"} | Attrs1], StateData};
"subscribe" -> "subscribe" ->
mod_roster:in_subscription(StateData#state.user,
{FU, FS, ""},
subscribe),
{true, Attrs, StateData}; {true, Attrs, StateData};
"subscribed" -> "subscribed" ->
mod_roster:in_subscription(StateData#state.user,
{FU, FS, ""},
subscribed),
{true, Attrs, StateData}; {true, Attrs, StateData};
"unsubscribe" -> "unsubscribe" ->
mod_roster:in_subscription(StateData#state.user,
{FU, FS, ""},
unsubscribe),
{true, Attrs, StateData}; {true, Attrs, StateData};
"unsubscribed" -> "unsubscribed" ->
mod_roster:in_subscription(StateData#state.user,
{FU, FS, ""},
unsubscribed),
{true, Attrs, StateData}; {true, Attrs, StateData};
_ -> _ ->
{true, Attrs, StateData} {true, Attrs, StateData}
@ -450,10 +440,17 @@ presence_update(From, Packet, StateData) ->
true -> true ->
StateData StateData
end, end,
StateData; StateData;
"error" -> "error" ->
StateData; StateData;
"subscribe" ->
StateData;
"subscribed" ->
StateData;
"unsubscribe" ->
StateData;
"unsubscribed" ->
StateData;
_ -> _ ->
FromUnavail = (StateData#state.pres_last == undefined) or FromUnavail = (StateData#state.pres_last == undefined) or
StateData#state.pres_invis, StateData#state.pres_invis,
@ -479,28 +476,36 @@ presence_update(From, Packet, StateData) ->
presence_track(From, To, Packet, StateData) -> presence_track(From, To, Packet, StateData) ->
{xmlelement, Name, Attrs, Els} = Packet, {xmlelement, Name, Attrs, Els} = Packet,
LTo = jlib:jid_tolower(To),
User = StateData#state.user,
case xml:get_attr_s("type", Attrs) of case xml:get_attr_s("type", Attrs) of
"unavailable" -> "unavailable" ->
I = remove_element(To, StateData#state.pres_i), I = remove_element(LTo, StateData#state.pres_i),
A = remove_element(To, StateData#state.pres_a), A = remove_element(LTo, StateData#state.pres_a),
StateData#state{pres_i = I, StateData#state{pres_i = I,
pres_a = A}; pres_a = A};
"invisible" -> "invisible" ->
I = ?SETS:add_element(To, StateData#state.pres_i), I = ?SETS:add_element(LTo, StateData#state.pres_i),
A = remove_element(To, StateData#state.pres_a), A = remove_element(LTo, StateData#state.pres_a),
StateData#state{pres_i = I, StateData#state{pres_i = I,
pres_a = A}; pres_a = A};
"subscribe" -> "subscribe" ->
mod_roster:out_subscription(User, To, subscribe),
StateData; StateData;
"subscribed" -> "subscribed" ->
mod_roster:out_subscription(User, To, subscribed),
StateData; StateData;
"unsubscribe" -> "unsubscribe" ->
mod_roster:out_subscription(User, To, unsubscribe),
StateData; StateData;
"unsubscribed" -> "unsubscribed" ->
mod_roster:out_subscription(User, To, unsubscribed),
StateData;
"error" ->
StateData; StateData;
_ -> _ ->
I = remove_element(To, StateData#state.pres_i), I = remove_element(LTo, StateData#state.pres_i),
A = ?SETS:add_element(To, StateData#state.pres_a), A = ?SETS:add_element(LTo, StateData#state.pres_a),
StateData#state{pres_i = I, StateData#state{pres_i = I,
pres_a = A} pres_a = A}
end. end.

View File

@ -100,17 +100,7 @@ do_route(From, To, Packet) ->
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, error} -> {atomic, error} ->
% TODO: start s2s instead of below
ejabberd_s2s ! {route, From, To, Packet}; ejabberd_s2s ! {route, From, To, Packet};
%{xmlelement, Name, Attrs, SubTags} = Packet,
%case xml:get_attr_s("type", Attrs) of
% "error" ->
% ok;
% _ ->
% Err = jlib:make_error_reply(Packet,
% "502", "Service Unavailable"),
% ejabberd_router ! {route, To, From, Err}
%end;
{atomic, {ok, Node, Pid}} -> {atomic, {ok, Node, Pid}} ->
case node() of case node() of
Node -> Node ->

View File

@ -186,26 +186,49 @@ wait_for_verification(closed, StateData) ->
stream_established({xmlstreamelement, El}, StateData) -> stream_established({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, Els} = El, {xmlelement, Name, Attrs, Els} = El,
% TODO case Name of
From = xml:get_attr_s("from", Attrs), "db:verify" ->
FromJID1 = jlib:string_to_jid(From), case is_key_packet(El) of
FromJID = case FromJID1 of {verify, To, From, Id, Key} ->
{Node, Server, Resource} -> io:format("VERIFY KEY: ~p~n", [{To, From, Id, Key}]),
if Server == StateData#state.server -> FromJID1; Key1 = ejabberd_s2s:get_key(From),
true -> error Type = if Key == Key1 -> "valid";
end; true -> "invalid"
_ -> error end,
end, send_element(StateData#state.socket,
To = xml:get_attr_s("to", Attrs), {xmlelement,
ToJID = case To of "db:verify",
"" -> error; [{"from", ?MYNAME},
_ -> jlib:string_to_jid(To) {"to", From},
end, {"id", Id},
if ((Name == "iq") or (Name == "message") or (Name == "presence")) and {"type", Type}],
(ToJID /= error) and (FromJID /= error) -> []});
ejabberd_router:route(FromJID, ToJID, El); _ ->
true -> ok
error end;
_ ->
From = xml:get_attr_s("from", Attrs),
FromJID1 = jlib:string_to_jid(From),
FromJID = case FromJID1 of
{Node, Server, Resource} ->
if Server == StateData#state.server -> FromJID1;
true -> error
end;
_ -> error
end,
To = xml:get_attr_s("to", Attrs),
ToJID = case To of
"" -> error;
_ -> jlib:string_to_jid(To)
end,
if ((Name == "iq") or
(Name == "message") or
(Name == "presence")) and
(ToJID /= error) and (FromJID /= error) ->
ejabberd_router:route(FromJID, ToJID, El);
true ->
error
end
end, end,
{next_state, stream_established, StateData}; {next_state, stream_established, StateData};

View File

@ -169,18 +169,45 @@ do_route(From, To, Packet) ->
% TODO % TODO
case Name of case Name of
"presence" -> "presence" ->
lists:foreach( {FU, FS, FR} = From,
fun(R) -> Pass = case xml:get_attr_s("type", Attrs) of
if From /= {User, Server, R} -> "subscribe" ->
ejabberd_sm ! {route, mod_roster:in_subscription(User,
From, {FU, FS, ""},
{User, Server, R}, subscribe);
Packet}; "subscribed" ->
true -> mod_roster:in_subscription(User,
ok {FU, FS, ""},
end subscribed);
end, get_user_resources(User)), "unsubscribe" ->
ok; mod_roster:in_subscription(User,
{FU, FS, ""},
unsubscribe);
"unsubscribed" ->
mod_roster:in_subscription(User,
{FU, FS, ""},
unsubscribed);
_ ->
true
end,
if Pass ->
LFrom = jlib:jid_tolower(From),
LUser = jlib:tolower(User),
LServer = jlib:tolower(Server),
lists:foreach(
fun(R) ->
if LFrom /= {LUser, LServer, R} ->
ejabberd_sm ! {route,
From,
{User, Server, R},
Packet};
true ->
ok
end
end, get_user_resources(User));
true ->
ok
end;
"message" -> "message" ->
% TODO % TODO
ok; ok;

View File

@ -20,6 +20,7 @@
string_to_jid/1, string_to_jid/1,
jid_to_string/1, jid_to_string/1,
tolower/1, tolower/1,
jid_tolower/1,
get_iq_namespace/1, get_iq_namespace/1,
iq_query_info/1, iq_query_info/1,
is_iq_request_type/1, is_iq_request_type/1,
@ -179,6 +180,8 @@ tolower(S) ->
lists:map(fun tolower_c/1, S). lists:map(fun tolower_c/1, S).
jid_tolower({U, S, R}) ->
{tolower(U), tolower(S), R}.
get_iq_namespace({xmlelement, Name, Attrs, Els}) when Name == "iq" -> get_iq_namespace({xmlelement, Name, Attrs, Els}) when Name == "iq" ->
case xml:remove_cdata(Els) of case xml:remove_cdata(Els) of

View File

@ -15,15 +15,18 @@
-export([start/0, init/0, -export([start/0, init/0,
process_iq/3, process_iq/3,
get_subscription_lists/1, get_subscription_lists/1,
in_subscription/3]). in_subscription/3,
out_subscription/3]).
-include_lib("mnemosyne/include/mnemosyne.hrl"). -include_lib("mnemosyne/include/mnemosyne.hrl").
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-record(roster, {user, -record(roster, {uj,
user,
jid, jid,
name = "", name = "",
subscription = none, subscription = none,
ask = none,
groups = [], groups = [],
xattrs = [], xattrs = [],
xs = []}). xs = []}).
@ -35,9 +38,8 @@ start() ->
init() -> init() ->
mnesia:create_table(roster,[{disc_copies, [node()]}, mnesia:create_table(roster,[{disc_copies, [node()]},
{type, bag},
{attributes, record_info(fields, roster)}]), {attributes, record_info(fields, roster)}]),
mnesia:add_table_index(roster, jid), mnesia:add_table_index(roster, user),
ejabberd_local:register_iq_handler("jabber:iq:roster", ejabberd_local:register_iq_handler("jabber:iq:roster",
?MODULE, process_iq), ?MODULE, process_iq),
loop(). loop().
@ -83,7 +85,7 @@ process_iq_get(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
{User, _, _} = From, {User, _, _} = From,
LUser = jlib:tolower(User), LUser = jlib:tolower(User),
F = fun() -> F = fun() ->
mnesia:read({roster, LUser}) mnesia:index_read(roster, LUser, #roster.user)
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, Items} -> {atomic, Items} ->
@ -108,15 +110,24 @@ item_to_xml(Item) ->
Attrs3 = case Item#roster.subscription of Attrs3 = case Item#roster.subscription of
none -> none ->
[{"subscription", "none"} | Attrs2]; [{"subscription", "none"} | Attrs2];
from ->
[{"subscription", "from"} | Attrs2];
to ->
[{"subscription", "to"} | Attrs2];
both -> both ->
[{"subscription", "both"} | Attrs2]; [{"subscription", "both"} | Attrs2];
remove -> remove ->
[{"subscription", "remove"} | Attrs2]; [{"subscription", "remove"} | Attrs2]
_ ->
% TODO
Attrs2
end, end,
Attrs = Attrs3 ++ Item#roster.xattrs, Attrs4 = case Item#roster.ask of
none ->
Attrs3;
subscribe ->
[{"ask", "subscribe"} | Attrs3];
unsubscribe ->
[{"ask", "unsubscribe"} | Attrs3]
end,
Attrs = Attrs4 ++ Item#roster.xattrs,
SubEls1 = lists:map(fun(G) -> SubEls1 = lists:map(fun(G) ->
{xmlelement, "group", [], [{xmlcdata, G}]} {xmlelement, "group", [], [{xmlcdata, G}]}
end, Item#roster.groups), end, Item#roster.groups),
@ -139,21 +150,18 @@ process_item_set(User, To, XItem) ->
error -> error ->
ok; ok;
_ -> _ ->
LJID = jlib:jid_tolower(JID),
F = fun() -> F = fun() ->
Res = mnemosyne:eval(query [X || X <- table(roster), Res = mnesia:read({roster, {LUser, LJID}}),
X.user = LUser,
X.jid = JID]
end),
Item = case Res of Item = case Res of
[] -> [] ->
#roster{user = LUser, #roster{uj = {LUser, LJID},
jid = JID, user = LUser,
groups = [], jid = JID};
xattrs = [],
xs = []};
[I] -> [I] ->
mnesia:delete_object(I), I#roster{user = LUser,
I#roster{name = "", jid = JID,
name = "",
groups = [], groups = [],
xattrs = [], xattrs = [],
xs = []} xs = []}
@ -162,7 +170,7 @@ process_item_set(User, To, XItem) ->
Item2 = process_item_els(Item1, Els), Item2 = process_item_els(Item1, Els),
case Item2#roster.subscription of case Item2#roster.subscription of
remove -> remove ->
ok; mnesia:delete({roster, {LUser, LJID}});
_ -> _ ->
mnesia:write(Item2) mnesia:write(Item2)
end, end,
@ -249,7 +257,7 @@ push_item(User, Resource, From, Item) ->
get_subscription_lists(User) -> get_subscription_lists(User) ->
LUser = jlib:tolower(User), LUser = jlib:tolower(User),
F = fun() -> F = fun() ->
mnesia:read({roster, LUser}) mnesia:index_read(roster, LUser, #roster.user)
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, Items} -> {atomic, Items} ->
@ -259,7 +267,8 @@ get_subscription_lists(User) ->
end. end.
fill_subscription_lists([I | Is], F, T) -> fill_subscription_lists([I | Is], F, T) ->
J = I#roster.jid, %J = I#roster.jid,
J = element(2, I#roster.uj),
case I#roster.subscription of case I#roster.subscription of
both -> both ->
fill_subscription_lists(Is, [J | F], [J | T]); fill_subscription_lists(Is, [J | F], [J | T]);
@ -276,14 +285,146 @@ fill_subscription_lists([], F, T) ->
in_subscription(User, From, Type) -> in_subscription(User, From, Type) ->
LUser = jlib:tolower(User), LUser = jlib:tolower(User),
LFrom = jlib:jid_tolower(From),
{FU, FS, FR} = From,
F = fun() -> F = fun() ->
mnesia:read({roster, LUser}) case mnesia:read({roster, {LUser, LFrom}}) of
[] ->
case Type of
subscribe ->
true;
unsubscribe ->
true;
unsubscribed ->
false;
subscribed ->
NewItem = #roster{uj = {LUser, LFrom},
user = LUser,
jid = From},
mnesia:write(NewItem),
true
end;
[I] ->
case Type of
subscribe ->
S = I#roster.subscription,
if
(S == both) or (S == from) ->
ejabberd_router:route(
{User, ?MYNAME, ""}, {FU, FS, ""},
{xmlelement, "presence",
[{"type", "subscribed"}], []}),
% TODO: update presence
false;
true ->
true
end;
unsubscribe ->
S = I#roster.subscription,
if
(S == none) or (S == to) ->
ejabberd_router:route(
{User, ?MYNAME, ""}, {FU, FS, ""},
{xmlelement, "presence",
[{"type", "unsubscribed"}], []}),
% TODO: update presence
false;
true ->
true
end;
_ ->
S = I#roster.subscription,
NS = case Type of
subscribed ->
case S of
from -> both;
none -> to;
_ -> S
end;
unsubscribed ->
case S of
both -> from;
to -> none;
_ -> S
end
end,
NewItem = I#roster{subscription = NS,
ask = none},
mnesia:write(NewItem),
{push, NewItem}
end
end
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, Items} -> {atomic, true} ->
% TODO true;
ok; {atomic, false} ->
false;
{atomic, {push, Item}} ->
push_item(User, {"", ?MYNAME, ""}, Item),
true;
_ -> _ ->
ok false
end.
out_subscription(User, JID, Type) ->
LUser = jlib:tolower(User),
LJID = jlib:jid_tolower(JID),
F = fun() ->
Item = case mnesia:read({roster, {LUser, LJID}}) of
[] ->
if (Type == unsubscribe) or
(Type == unsubscribed) ->
false;
true ->
#roster{uj = {LUser, LJID},
user = LUser,
jid = JID}
end;
[I] ->
I
end,
if Item == false ->
ok;
true ->
NewItem =
case Type of
subscribe ->
Item#roster{ask = subscribe};
unsubscribe ->
Item#roster{ask = unsubscribe};
subscribed ->
S = Item#roster.subscription,
NS = case S of
to -> both;
none -> from;
_ -> S
end,
% TODO: update presence
Item#roster{subscription = NS,
ask = none};
unsubscribed ->
S = Item#roster.subscription,
NS = case S of
both -> to;
from -> none;
_ -> S
end,
% TODO: update presence
Item#roster{subscription = NS,
ask = none}
end,
mnesia:write(NewItem),
{push, NewItem}
end
end,
case mnesia:transaction(F) of
{atomic, ok} ->
ok;
{atomic, {push, Item}} ->
push_item(User, {"", ?MYNAME, ""}, Item),
true;
_ ->
false
end. end.

42
src/sha.erl Normal file
View File

@ -0,0 +1,42 @@
%%%----------------------------------------------------------------------
%%% File : sha.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose :
%%% Created : 20 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$
%%%----------------------------------------------------------------------
-module(sha).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-export([start/0, init/0, sha/1]).
start() ->
register(sha, spawn(?MODULE, init, [])).
init() ->
ok = erl_ddll:load_driver(".", sha_erl),
Port = open_port({spawn, sha_erl}, [binary]),
loop(Port).
loop(Port) ->
receive
{From, {text, Str}} ->
Port ! {self(), {command, Str}},
SHA = receive
{Port, {data, Bin}} ->
binary_to_term(Bin)
end,
From ! {sha, SHA},
loop(Port)
end.
sha(Text) ->
sha ! {self(), {text, Text}},
receive
{sha, S} ->
S
end.