mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-24 17:29:28 +01:00
*** empty log message ***
SVN Revision: 20
This commit is contained in:
parent
0e363bf8cb
commit
ae30798efd
271
sha_erl.c
Normal file
271
sha_erl.c
Normal 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;
|
||||
}
|
||||
|
18
src/Makefile
18
src/Makefile
@ -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 \
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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),
|
||||
|
@ -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.
|
||||
|
@ -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 ->
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
42
src/sha.erl
Normal 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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user