*** 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
all: expat_erl.so
ERLSHLIBS = expat_erl.so sha_erl.so
all: $(ERLSHLIBS)
erl -make
expat_erl.so: expat_erl.c
gcc -Wall $(INCLUDES) $(LIBDIRS) \
-lexpat \
expat_erl.c \
-lerl_interface \
-lei \
-o expat_erl.so -fpic -shared \
$(ERLSHLIBS): %.so: %.c
gcc -Wall $(INCLUDES) $(LIBDIRS) \
-lexpat \
$(subst .so,.c,$@) \
-lerl_interface \
-lei \
-o $@ -fpic -shared \

View File

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

View File

@ -19,6 +19,7 @@
-export([start/0, start_link/0,
set_password/2,
check_password/2,
check_password/4,
try_register/2]).
%% gen_server callbacks
@ -110,6 +111,31 @@ check_password(User, Password) ->
false
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) ->
LUser = jlib:tolower(User),

View File

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

View File

@ -100,17 +100,7 @@ do_route(From, To, Packet) ->
end,
case mnesia:transaction(F) of
{atomic, error} ->
% TODO: start s2s instead of below
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}} ->
case node() of
Node ->

View File

@ -186,26 +186,49 @@ wait_for_verification(closed, StateData) ->
stream_established({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, Els} = El,
% TODO
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
case Name of
"db:verify" ->
case is_key_packet(El) of
{verify, To, From, Id, Key} ->
io:format("VERIFY KEY: ~p~n", [{To, From, Id, Key}]),
Key1 = ejabberd_s2s:get_key(From),
Type = if Key == Key1 -> "valid";
true -> "invalid"
end,
send_element(StateData#state.socket,
{xmlelement,
"db:verify",
[{"from", ?MYNAME},
{"to", From},
{"id", Id},
{"type", Type}],
[]});
_ ->
ok
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,
{next_state, stream_established, StateData};

View File

@ -169,18 +169,45 @@ do_route(From, To, Packet) ->
% TODO
case Name of
"presence" ->
lists:foreach(
fun(R) ->
if From /= {User, Server, R} ->
ejabberd_sm ! {route,
From,
{User, Server, R},
Packet};
true ->
ok
end
end, get_user_resources(User)),
ok;
{FU, FS, FR} = From,
Pass = case xml:get_attr_s("type", Attrs) of
"subscribe" ->
mod_roster:in_subscription(User,
{FU, FS, ""},
subscribe);
"subscribed" ->
mod_roster:in_subscription(User,
{FU, FS, ""},
subscribed);
"unsubscribe" ->
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" ->
% TODO
ok;

View File

@ -20,6 +20,7 @@
string_to_jid/1,
jid_to_string/1,
tolower/1,
jid_tolower/1,
get_iq_namespace/1,
iq_query_info/1,
is_iq_request_type/1,
@ -179,6 +180,8 @@ tolower(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" ->
case xml:remove_cdata(Els) of

View File

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

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.