I try to get TO: user#mail.com field from mime mail message.
I have code:
parse_to(Data) ->
List = string:tokens(Data, ":"),
Sep1 = lists:map(fun(H) ->string:tokens(H, ":") end, List),
io:format(Sep1),
Sep2 = lists:filter(fun ([K | _]) -> K == "To" end, Sep1),
ListAddress = lists:append(Sep2),
[_ | Tail] = ListAddress,
lists:map(fun(Address) -> string:tokens(Address, ",") end, Tail).
If i have short message for example: https://gist.github.com/865910
I got in io:format(Sep1) https://gist.github.com/865905, it's ok all without :
But if i have long message with attachment: - https://gist.github.com/865914
I got in io:format(Sep1) - https://gist.github.com/865906 everything remains the same as it was with :
What's wrong? Why shot message normal parse and big message not parsed?
When i try use regexp:
List = binary_to_list(Binary),
re:run(List, "^To: (.)*$", [multiline, {capture, all_but_first, list}]).
I get only {match, ["m"]}
Why?
Thank you.
Try a regular expression:
1> Data = <<"...">> % Your long message
<<"...">>
2> re:run(Data, <<"^To: (.*)$">>, [multiline, {capture, all_but_first, binary}]).
{match,[<<"shk#shk.dyndns-mail.com">>]}
Related
I am writing a chat communication app.
If the user's unique id is given in Base 64 GUID format, it is throwing bad_username error.
In this file: https://pow.gs/mirror/ejabberd/-/blob/fd8e07af4789be362a61755ea47f216baeb64989/src/cyrsasl_scram.erl, there is a method to remove the == from username:
unescape_username(<<"">>) -> <<"">>;
unescape_username(EscapedUsername) ->
Pos = str:str(EscapedUsername, <<"=">>),
if Pos == 0 -> EscapedUsername;
true ->
Start = str:substr(EscapedUsername, 1, Pos - 1),
End = str:substr(EscapedUsername, Pos),
EndLen = byte_size(End),
if EndLen < 3 -> error;
true ->
case str:substr(End, 1, 3) of
<<"=2C">> ->
<<Start/binary, ",",
(unescape_username(str:substr(End, 4)))/binary>>;
<<"=3D">> ->
<<Start/binary, "=",
(unescape_username(str:substr(End, 4)))/binary>>;
_Else -> error
end
end
end.
I don't know why this has been written. If I remove this particular code, the connection is working fine. Please let me know why it is restricted.
If the users' unique id is given in Base 64 GUID format, it is throwing bad_username error.
Right:
call xmpp_sasl_scram:unescape_username(<<"user1">>)
returned from xmpp_sasl_scram:unescape_username/1 -> <<"user1">>
call xmpp_sasl_scram:unescape_username(<<"user3==ABC">>)
returned from xmpp_sasl_scram:unescape_username/1 -> error
call xmpp_sasl_scram:unescape_username(<<"user4=DEF">>)
returned from xmpp_sasl_scram:unescape_username/1 -> error
call xmpp_sasl_scram:unescape_username(<<"user5=">>)
returned from xmpp_sasl_scram:unescape_username/1 -> error
I don't know why this has been written. If I remove this particular code, the connection is working fine. Please let me know why it is restricted.
I don't know, either. But that code exists since nine years ago:
https://github.com/processone/ejabberd/commit/e80b92b48148505b44c6a378db36badfe60fce79#diff-5c51943c1268ffe26fe3b041b20675c6R136
Whatever reason there is for it, it's obviously a good reason.
I query the list of users from Mnesia Database in Chicagoboss. I'm getting the error when I try to add the Lists within lists:foreach with ++ operator. My aim is, based on userid I will do ets:lookup to my cache and create a List like - [{{<<"name">>,<<"Batman">>}, {<<"steps">>,2552}, {<<"distance">>,2050}}].
For each user I'll create this list and add with the previous List. So that ultimately I can can sort on <<"steps">> and convert the binary list by json encoding and send it to the client via Websockets.
I'm getting the error at this line:
Reading1 = Reading2 ++ Currentlist
as I've decalred Reading1 as an Empty list.
My question is how can I manipulate the lists within the lists:foreach and then send the result List via websocket?
BelugaUsers = boss_db:find(users, [{accesstoken, 'not_equals', ''}]),
Reading1 = [],
Reading2 = [],
lists:foreach(fun(X) ->
{_,_,BEmail,BName,_,_,BAccessToken,_} = X,
UserKey = BEmail ++ "-" ++ ?MYAPICALL1,
io:format("UserKey for Leader Board: ~n~p~n",[UserKey]),
[Reading] = ets:lookup(myapi_cache, list_to_binary(UserKey)),
{_,Result} = Reading,
ActivitySummary = proplists:get_value(<<"activitySummary">>, Result),
%Print ActivitySummary for the user ....printing fine
io:format("ActivitySummary ==========: ~n~p~n",[ActivitySummary]),
%Create a list of the format
%[{{<<"name">>,<<"Batman">>}, {<<"steps">>,2552}, {<<"distance">>,2050}}]
Currentlist = [{{<<"name">>, list_to_binary(BName)}, {<<"steps">>, proplists:get_value(<<"steps">>, ActivitySummary)}, {<<"distance">>, proplists:get_value(<<"distance">>, ActivitySummary)}}],
%% HERE I'M GETTING error%%
Reading1 = Reading2 ++ Currentlist
end, BelugaUsers),
%sort the list
Reading3 = lists:keysort(2, Reading1),
%reverse the list
Reading4 = lists:reverse(Reading3),
WebSocketId ! {text, jsx:encode(Reading4)},
Erlang variables are single-assignment; once bound to a value, they can't be re-bound to a different value.
The lists:foreach/2 function is not useful for this problem because it can't create a new value and return it to its caller. You should instead use lists:map/2, perhaps like this:
BelugaUsers = boss_db:find(users, [{accesstoken, 'not_equals', ''}]),
Reading = lists:map(
fun(X) ->
{_,_,BEmail,BName,_,_,BAccessToken,_} = X,
UserKey = BEmail ++ "-" ++ ?MYAPICALL1,
io:format("UserKey for Leader Board: ~n~p~n",[UserKey]),
{_,Result} = hd(ets:lookup(myapi_cache, list_to_binary(UserKey))),
ActivitySummary = proplists:get_value(<<"activitySummary">>, Result),
%%Print ActivitySummary for the user ....printing fine
io:format("ActivitySummary ==========: ~n~p~n",[ActivitySummary]),
%%Create a tuple of the format
%%{{<<"name">>,<<"Batman">>}, {<<"steps">>,2552}, {<<"distance">>,2050}}
{{<<"name">>, list_to_binary(BName)},
{<<"steps">>, proplists:get_value(<<"steps">>, ActivitySummary)},
{<<"distance">>, proplists:get_value(<<"distance">>, ActivitySummary)}}
end, BelugaUsers),
%%sort the list
Reading2 = lists:keysort(2, Reading),
%%reverse the list
Reading3 = lists:reverse(Reading2),
WebSocketId ! {text, jsx:encode(Reading3)}.
The lists:map/2 function applies a function to each value in a list to a produce a potentially different value and returns a new list consisting of those new values. This is essentially what you were trying to do with lists:foreach/2 and your attempt to use imperative assignment to add each element to an already-existing list.
You could alternatively use a list comprehension but I think lists:map/2 is clearer in this situation.
I am using ejabberd hook named "filter-packet" to make a module. Here I want to add an element to packet. How to do it? My Code is -
on_filter_packet({From, To, Packet}=Input) ->
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
if (Type == <<"groupchat">>) ->
?INFO_MSG("type is group chat", []),
NPacket={Packet, [{xmlelement, "time",
[],
[{xmlcdata, "testtime"}]}]},
{From, To, NPacket};
true ->
Input
end.
This code is giving error of bad match. Any Help ?
13.12 uses different type for xmlelement.
Packet is a type of record #xmlel, so you need to insert new element to Packet#xmlel.children.
on_filter_packet({From, To, #xmlel{ children=OldChildren } = Packet}=Input) ->
...
TimeElem = #xmlel{ name = <<"time">>,
children =
[{xmlcdata, <<"testtime">>}]},
NPacket = Packet#xmlel{ children = [TimeElem|OldChildren] },
...
Not tested, but will work.
a table named "md" with structure {id,name},I want read records from md use paging query,I tried mnesia:select/4 and mnesia:select/1 as below:
%% first use select/2: "ID < 10",returned [1,2,4,3,8,5,9,7,6]
(ejabberd#localhost)5> mnesia:activity(transaction,fun mnesia:select/2,md, [{{md,'$1','_'},[{'<','$1',10}],['$1']}]).
{atomic,[1,2,4,3,8,5,9,7,6]}
%%but when query with select/4,returned [6], why?
(ejabberd#localhost)7> {atomic,{R1,C1}}=mnesia:activity(transaction,fun mnesia:select/4,md,[{{md,'$1','_'},[{'<','$1',10}],['$1']}],5,read).
{atomic,{[6],
{mnesia_select,md,
{tid,10535470,<0.460.0>},
ejabberd#localhost,disc_only_copies,
{dets_cont,select,5,
<<0,0,0,29,18,52,86,120,0,0,0,21,131,104,3,...>>,
{141720,148792,<<>>},
md,<0.130.0>,<<>>},
[],undefined,undefined,
[{{md,'$1','_'},[{'<','$1',10}],['$1']}]}}}
%% and then use mnesia:select/1 with continuation "C1",got wrong_transaction
(ejabberd#localhost)8> mnesia:activity(transaction,fun mnesia:select/1,C1).
{aborted,wrong_transaction}
how to use mnesia:select/4 and mnesia:select/1 for paging query?
You will have to call select/1 inside the same transaction.
Otherwise the table can change between invocations to select/4 and select/1.
You must use a dirty context if you want to use is as written above.
here is my solution:
use async_dirty instead of transaction
{Record,Cont}=mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read])
then read next Limit number of records:
mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])
full code:
-record(md,{id,name}).
batch_delete(Id,Limit) ->
Match_head = #md{id='$1',name='$2'},
Guard = {'<','$1',Id},
Result = '$_',
{Record,Cont} = mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read]),
delete_next({Record,Cont}).
delete_next('$end_of_table') ->
over;
delete_next({Record,Cont}) ->
delete(Record),
delete_next(mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])).
delete(Records) ->
io:format("delete(~p)~n",[Records]),
F = fun() ->
[ mnesia:delete_object(O) || O <- Records]
end,
mnesia:transaction(F).
I'm trying to extract the second link under the description tag. I have written the following code, but it looks really messy with freads and substrings (just to get it to work). Is there any cleaner way to accomplish this?
magic(Url)->
Tag = ".xml",
inets:start(),
{ ok, {Status, Headers, Body }} = httpc:request(Url ++ Tag),
{ Xml, Rest } = xmerl_scan:string(Body),
{xmlObj , string , A } = xmerl_xpath:string("substring-after(substring-after(substring->before(//channel/item/description[1], '\">[link]') , 'br') , 'href=')", Xml),
{ok,_,B} = io_lib:fread("~6s" , A),
string:sub_string(B,1,string:len(B)-1).
Not a perfect solution, but you may use such xpaths
//channel/item/description[1]/text()[16] and //channel/item/description[1]/text()[24]
extracted strings contains urls + quotes at the beginning, so you may use list matching syntax to cut off quotation marks: [_|Url] = ...
So use this: [{_,_,_,_,[_|U1],_}] = xmerl_xpath:string("//channel/item/description[1]/text()[16]", Xml). to bind U1 with first url.
Test in shell:
11> [{_,_,_,_,[_|U1],_}] = xmerl_xpath:string("//channel/item/description[1]/text()[16]", Xml).
[{xmlText,[{description,5},{item,5},{channel,1},{rss,1}],
16,[],"\"http://www.reddit.com/user/escaped_reddit",text}]
12>
12> U1.
"http://www.reddit.com/user/escaped_reddit"
13>
13>
13> [{_,_,_,_,[_|U2],_}] = xmerl_xpath:string("//channel/item/description[1]/text()[24]", Xml).
[{xmlText,[{description,5},{item,5},{channel,1},{rss,1}],
24,[],
"\"http://www.reddit.com/r/erlang/comments/y62wf/how_to_use_ranch/",
text}]
14>
14> U2.
"http://www.reddit.com/r/erlang/comments/y62wf/how_to_use_ranch/"