aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Romain <christophe.romain@process-one.net>2017-09-27 11:12:09 +0200
committerChristophe Romain <christophe.romain@process-one.net>2017-09-27 11:12:09 +0200
commitc1d3d1318e40bd9a22525e2ae44f17aedc728269 (patch)
treebef342f80b78c4db624a00ffbd656432abec2445
parentPubSub: add correct order when requesting all items (diff)
parentAdd support for XEP-0368: SRV records for XMPP over TLS (diff)
Merge branch 'master' of github.com:processone/ejabberd
-rw-r--r--Makefile.in2
-rw-r--r--contrib/extract_translations/README21
-rw-r--r--contrib/extract_translations/extract_translations.erl307
-rwxr-xr-xcontrib/extract_translations/prepare-translation.sh366
-rw-r--r--rebar.config2
-rw-r--r--src/mod_http_upload.erl2
-rw-r--r--src/xmpp_stream_out.erl91
-rwxr-xr-xtools/prepare-tr.sh100
8 files changed, 168 insertions, 723 deletions
diff --git a/Makefile.in b/Makefile.in
index 3bee2f649..76c38043a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -102,7 +102,7 @@ xref: all
translations:
- contrib/extract_translations/prepare-translation.sh -updateall
+ tools/prepare-tr.sh
edoc:
$(ERL) -noinput +B -eval \
diff --git a/contrib/extract_translations/README b/contrib/extract_translations/README
deleted file mode 100644
index 9278dd106..000000000
--- a/contrib/extract_translations/README
+++ /dev/null
@@ -1,21 +0,0 @@
-extract_translations - auxiliary tool that extracts lines to be translated
-from ejabberd source tree.
-
-Building:
- erlc extract_translations.erl
-
-Invoking 1:
- erl -noinput -s extract_translations -extra dirname message_file
-
- where dirname is the directory "src" in ejabberd's source tree root,
- message_file is a file with translated messages (src/msgs/*.msg).
-
- Result is a list of messages from source files which aren't contained in
- message file.
-
-Invoking 2:
- erl -noinput -s extract_translations -extra -unused dirname message_file
-
- Result is a list of messages from message file which aren't in source
- files anymore.
-
diff --git a/contrib/extract_translations/extract_translations.erl b/contrib/extract_translations/extract_translations.erl
deleted file mode 100644
index 70304761a..000000000
--- a/contrib/extract_translations/extract_translations.erl
+++ /dev/null
@@ -1,307 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File : extract_translations.erl
-%%% Author : Sergei Golovan <sgolovan@nes.ru>
-%%% Purpose : Auxiliary tool for interface/messages translators
-%%% Created : 23 Apr 2005 by Sergei Golovan <sgolovan@nes.ru>
-%%% Id : $Id$
-%%%----------------------------------------------------------------------
-
--module(extract_translations).
--author('sgolovan@nes.ru').
-
--export([start/0]).
-
--define(STATUS_SUCCESS, 0).
--define(STATUS_ERROR, 1).
--define(STATUS_USAGE, 2).
-
--include_lib("kernel/include/file.hrl").
-
-
-start() ->
- ets:new(translations, [named_table, public]),
- ets:new(translations_obsolete, [named_table, public]),
- ets:new(files, [named_table, public]),
- ets:new(vars, [named_table, public]),
- case init:get_plain_arguments() of
- ["-srcmsg2po", Dir, File] ->
- print_po_header(File),
- Status = process(Dir, File, srcmsg2po),
- halt(Status);
- ["-unused", Dir, File] ->
- Status = process(Dir, File, unused),
- halt(Status);
- [Dir, File] ->
- Status = process(Dir, File, used),
- halt(Status);
- _ ->
- print_usage(),
- halt(?STATUS_USAGE)
- end.
-
-
-process(Dir, File, Used) ->
- case load_file(File) of
- {error, Reason} ->
- io:format("~s: ~s~n", [File, file:format_error(Reason)]),
- ?STATUS_ERROR;
- _ ->
- FileList = find_src_files(Dir),
- lists:foreach(
- fun(F) ->
- parse_file(Dir, F, Used)
- end, FileList),
- case Used of
- unused ->
- ets:foldl(fun({Key, _}, _) ->
- io:format("~p~n", [Key])
- end, ok, translations);
- srcmsg2po ->
- ets:foldl(fun({Key, Trans}, _) ->
- print_translation_obsolete(Key, Trans)
- end, ok, translations_obsolete);
- _ ->
- ok
- end,
- ?STATUS_SUCCESS
- end.
-
-parse_file(Dir, File, Used) ->
- ets:delete_all_objects(vars),
- case epp:parse_file(File, [Dir, filename:dirname(File) | code:get_path()], []) of
- {ok, Forms} ->
- lists:foreach(
- fun(F) ->
- parse_form(Dir, File, F, Used)
- end, Forms);
- _ ->
- ok
- end.
-
-parse_form(Dir, File, Form, Used) ->
- case Form of
- %%{undefined, Something} ->
- %% io:format("Undefined: ~p~n", [Something]);
- {call,
- _,
- {remote, _, {atom, _, translate}, {atom, _, translate}},
- [_, {string, Line, Str}]
- } ->
- process_string(Dir, File, Line, Str, Used);
- {call,
- _,
- {remote, _, {atom, _, translate}, {atom, _, translate}},
- [_,
- {bin,_,
- [{bin_element,_,
- {string,Line,Str},
- default,default}]}]
- } ->
- process_string(Dir, File, Line, Str, Used);
- {call,
- _,
- {remote, _, {atom, _, translate}, {atom, _, translate}},
- [_, {var, _, Name}]
- } ->
- case ets:lookup(vars, Name) of
- [{_Name, Value, Line}] ->
- process_string(Dir, File, Line, Value, Used);
- _ ->
- ok
- end;
- {match,
- _,
- {var, _, Name},
- {string, Line, Value}
- } ->
- ets:insert(vars, {Name, Value, Line});
- {match,
- _,
- {var, _, Name},
- {bin,Line,[{bin_element,_,{string,_,Value},_,_}]}
- } ->
- ets:insert(vars, {Name, Value, Line});
- L when is_list(L) ->
- lists:foreach(
- fun(F) ->
- parse_form(Dir, File, F, Used)
- end, L);
- T when is_tuple(T) ->
- lists:foreach(
- fun(F) ->
- parse_form(Dir, File, F, Used)
- end, tuple_to_list(T));
- _ ->
- ok
- end.
-
-process_string(_Dir, _File, _Line, "", _Used) ->
- ok;
-
-process_string(_Dir, File, Line, Str, Used) ->
- case {ets:lookup(translations, Str), Used} of
- {[{_Key, _Trans}], unused} ->
- ets:delete(translations, Str);
- {[{_Key, _Trans}], used} ->
- ok;
- {[{_Key, Trans}], srcmsg2po} ->
- ets:delete(translations_obsolete, Str),
- print_translation(File, Line, Str, Trans);
- {_, used} ->
- case ets:lookup(files, File) of
- [{_}] ->
- ok;
- _ ->
- io:format("~n% ~s~n", [File]),
- ets:insert(files, {File})
- end,
- case Str of
- [] -> ok;
- _ -> io:format("{~p, \"\"}.~n", [Str])
- end,
- ets:insert(translations, {Str, ""});
- {_, srcmsg2po} ->
- case ets:lookup(files, File) of
- [{_}] ->
- ok;
- _ ->
- ets:insert(files, {File})
- end,
- ets:insert(translations, {Str, ""}),
- print_translation(File, Line, Str, "");
- _ ->
- ok
- end.
-
-load_file(File) ->
- case file:consult(File) of
- {ok, Terms} ->
- lists:foreach(
- fun({Orig, Trans}) ->
- case Trans of
- "" ->
- ok;
- _ ->
- ets:insert(translations, {Orig, Trans}),
- ets:insert(translations_obsolete, {Orig, Trans})
- end
- end, Terms);
- Err ->
- Err
- end.
-
-find_src_files(Dir) ->
- case file:list_dir(Dir) of
- {ok, FileList} ->
- recurse_filelist(
- lists:map(
- fun(F) ->
- filename:join(Dir, F)
- end, FileList));
- _ ->
- []
- end.
-
-recurse_filelist(FileList) ->
- recurse_filelist(FileList, []).
-
-recurse_filelist([], Acc) ->
- lists:reverse(Acc);
-
-recurse_filelist([H | T], Acc) ->
- case file:read_file_info(H) of
- {ok, #file_info{type = directory}} ->
- recurse_filelist(T, lists:reverse(find_src_files(H)) ++ Acc);
- {ok, #file_info{type = regular}} ->
- case string:substr(H, string:len(H) - 3) of
- ".erl" ->
- recurse_filelist(T, [H | Acc]);
- ".hrl" ->
- recurse_filelist(T, [H | Acc]);
- _ ->
- recurse_filelist(T, Acc)
- end;
- _ ->
- recurse_filelist(T, Acc)
- end.
-
-
-print_usage() ->
- io:format(
- "Usage: extract_translations [-unused] dir file~n"
- "~n"
- "Example:~n"
- " extract_translations . ./msgs/ru.msg~n"
- ).
-
-
-%%%
-%%% Gettext
-%%%
-
-print_po_header(File) ->
- MsgProps = get_msg_header_props(File),
- {Language, [LastT | AddT]} = prepare_props(MsgProps),
- print_po_header(Language, LastT, AddT).
-
-get_msg_header_props(File) ->
- {ok, F} = file:open(File, [read]),
- Lines = get_msg_header_props(F, []),
- file:close(F),
- Lines.
-
-get_msg_header_props(F, Lines) ->
- String = io:get_line(F, ""),
- case io_lib:fread("% ", String) of
- {ok, [], RemString} ->
- case io_lib:fread("~s", RemString) of
- {ok, [Key], Value} when Value /= "\n" ->
- %% The first character in Value is a blankspace:
- %% And the last characters are 'slash n'
- ValueClean = string:substr(Value, 2, string:len(Value)-2),
- get_msg_header_props(F, Lines ++ [{Key, ValueClean}]);
- _ ->
- get_msg_header_props(F, Lines)
- end;
- _ ->
- Lines
- end.
-
-prepare_props(MsgProps) ->
- Language = proplists:get_value("Language:", MsgProps),
- Authors = proplists:get_all_values("Author:", MsgProps),
- {Language, Authors}.
-
-print_po_header(Language, LastTranslator, AdditionalTranslatorsList) ->
- AdditionalTranslatorsString = build_additional_translators(AdditionalTranslatorsList),
- HeaderString =
- "msgid \"\"\n"
- "msgstr \"\"\n"
- ++ "\"X-Language: " ++ Language ++ "\\n\"\n"
- "\"Last-Translator: " ++ LastTranslator ++ "\\n\"\n"
- ++ AdditionalTranslatorsString ++
- "\"MIME-Version: 1.0\\n\"\n"
- "\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
- "\"Content-Transfer-Encoding: 8bit\\n\"\n",
- io:format("~s~n", [HeaderString]).
-
-build_additional_translators(List) ->
- lists:foldl(
- fun(T, Str) ->
- Str ++ "\"X-Additional-Translator: " ++ T ++ "\\n\"\n"
- end,
- "",
- List).
-
-print_translation(File, Line, Str, StrT) ->
- StrQ = ejabberd_regexp:greplace(list_to_binary(Str), <<"\\\"">>, <<"\\\\\"">>),
- StrTQ = ejabberd_regexp:greplace(list_to_binary(StrT), <<"\\\"">>, <<"\\\\\"">>),
- io:format("#: ~s:~p~nmsgid \"~s\"~nmsgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]).
-
-print_translation_obsolete(Str, StrT) ->
- File = "unknown.erl",
- Line = 1,
- StrQ = ejabberd_regexp:greplace(Str, "\\\"", "\\\\\""),
- StrTQ = ejabberd_regexp:greplace(StrT, "\\\"", "\\\\\""),
- io:format("#: ~s:~p~n#~~ msgid \"~s\"~n#~~ msgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]).
-
diff --git a/contrib/extract_translations/prepare-translation.sh b/contrib/extract_translations/prepare-translation.sh
deleted file mode 100755
index 98c282cc1..000000000
--- a/contrib/extract_translations/prepare-translation.sh
+++ /dev/null
@@ -1,366 +0,0 @@
-#!/bin/bash
-
-# Frontend for ejabberd's extract_translations.erl
-# by Badlop
-
-# How to create template files for a new language:
-# NEWLANG=zh
-# cp msgs/ejabberd.pot msgs/$NEWLANG.po
-# echo \{\"\",\"\"\}. > msgs/$NEWLANG.msg
-# ../../extract_translations/prepare-translation.sh -updateall
-
-prepare_dirs ()
-{
- # Where is Erlang binary
- ERL=`which erl`
-
- EJA_SRC_DIR=$EJA_DIR/src/
- EJA_MSGS_DIR=$EJA_DIR/priv/msgs/
- EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/
- EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl
- EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam
-
- SRC_DIR=$RUN_DIR/src
- EBIN_DIR=$RUN_DIR/ebin
- MSGS_DIR=$EJA_DIR/priv/msgs
-
- if !([[ -n $EJA_DIR ]])
- then
- echo "ejabberd dir does not exist: $EJA_DIR"
- fi
-
- if !([[ -x $EXTRACT_BEAM ]])
- then
- sh -c "cd $EXTRACT_DIR; $ERL -compile $EXTRACT_ERL"
- fi
-}
-
-extract_lang ()
-{
- MSGS_FILE=$1
- MSGS_FILE2=$MSGS_FILE.translate
- MSGS_PATH=$MSGS_DIR/$MSGS_FILE
- MSGS_PATH2=$MSGS_DIR/$MSGS_FILE2
-
- echo -n "Extracting language strings for '$MSGS_FILE':"
-
- echo -n " new..."
- cd $SRC_DIR
- $ERL -pa $EXTRACT_DIR -noinput -noshell -s extract_translations -s init stop -extra . $MSGS_PATH >$MSGS_PATH.new
- sed -e 's/^% \.\//% /g;' $MSGS_PATH.new > $MSGS_PATH.new2
- mv $MSGS_PATH.new2 $MSGS_PATH.new
-
- echo -n " old..."
- $ERL -pa $EXTRACT_DIR -noinput -noshell -s extract_translations -s init stop -extra -unused . $MSGS_PATH >$MSGS_PATH.unused
- find_unused_full $MSGS_FILE $MSGS_FILE.unused
-
- echo "" >$MSGS_PATH2
- echo " ***** Translation file for ejabberd ***** " >>$MSGS_PATH2
- echo "" >>$MSGS_PATH2
-
- echo "" >>$MSGS_PATH2
- echo " *** New strings: Can you please translate them? *** " >>$MSGS_PATH2
- cat $MSGS_PATH.new >>$MSGS_PATH2
-
- echo "" >>$MSGS_PATH2
- echo "" >>$MSGS_PATH2
- echo " *** Unused strings: They will be removed automatically *** " >>$MSGS_PATH2
- cat $MSGS_PATH.unused.full >>$MSGS_PATH2
-
- echo "" >>$MSGS_PATH2
- echo "" >>$MSGS_PATH2
- echo " *** Already translated strings: you can also modify any of them if you want *** " >>$MSGS_PATH2
- echo "" >>$MSGS_PATH2
- cat $MSGS_PATH.old_cleaned >>$MSGS_PATH2
-
- echo " ok"
-
- rm $MSGS_PATH.new
- rm $MSGS_PATH.old_cleaned
- rm $MSGS_PATH.unused.full
-}
-
-extract_lang_all ()
-{
- cd $MSGS_DIR
- for i in $( ls *.msg ) ; do
- extract_lang $i;
- done
-
- echo -e "File\tMissing\tLanguage\t\tLast translator"
- echo -e "----\t-------\t--------\t\t---------------"
- cd $MSGS_DIR
- for i in $( ls *.msg ) ; do
- MISSING=`cat $i.translate | grep "\", \"\"}." | wc -l`
- LANGUAGE=`grep "X-Language:" $i.translate | sed 's/% Language: //g'`
- LASTAUTH=`grep "Author:" $i.translate | head -n 1 | sed 's/% Author: //g'`
- echo -e "$i\t$MISSING\t$LANGUAGE\t$LASTAUTH"
- done
-
- cd $MSGS_DIR
- REVISION=`git describe --always`
- zip $HOME/ejabberd-langs-$REVISION.zip *.translate;
-
- rm *.translate
-}
-
-find_unused_full ()
-{
- DATFILE=$1
- DATFILEI=$1.old_cleaned
- DELFILE=$2
- cd msgs
-
- DATFILE1=$DATFILE.t1
- DATFILE2=$DATFILE.t2
-
- DELFILE1=$DELFILE.t1
- DELFILE2=$DELFILE.t2
- DELFILEF=$DATFILE.unused.full
- echo "" >$DELFILEF
-
- grep -v "\\\\" $DELFILE >$DELFILE2
- echo ENDFILEMARK >>$DELFILE2
- cp $DATFILE $DATFILEI
- cp $DATFILE $DATFILE2
-
- cp $DELFILE2 $DELFILE1
- STRING=`head -1 $DELFILE1`
- until [[ $STRING == ENDFILEMARK ]]; do
- cp $DELFILE2 $DELFILE1
- cp $DATFILE2 $DATFILE1
-
- STRING=`head -1 $DELFILE1`
-
- cat $DATFILE1 | grep "$STRING" >>$DELFILEF
- cat $DATFILE1 | grep -v "$STRING" >$DATFILE2
- cat $DELFILE1 | grep -v "$STRING" >$DELFILE2
- done
-
- mv $DATFILE2 $DATFILEI
-
- rm -f $MSGS_PATH.t1
- rm $MSGS_PATH.unused
- rm -f $MSGS_PATH.unused.t1
- rm $MSGS_PATH.unused.t2
-
- cd ..
-}
-
-extract_lang_srcmsg2po ()
-{
- LANG=$1
- LANG_CODE=$LANG.$PROJECT
- MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg
- PO_PATH=$MSGS_DIR/$LANG_CODE.po
-
- echo $MSGS_PATH
-
- cd $SRC_DIR
- $ERL -pa $EXTRACT_DIR -pa $EBIN_DIR -pa $EJA_SRC_DIR -pa ../include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$PO_PATH.1
- sed -e 's/ \[\]$/ \"\"/g;' $PO_PATH.1 > $PO_PATH.2
- msguniq --sort-by-file $PO_PATH.2 --output-file=$PO_PATH
-
- rm $PO_PATH.*
-}
-
-extract_lang_src2pot ()
-{
- LANG_CODE=$PROJECT
- MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg
- POT_PATH=$MSGS_DIR/$LANG_CODE.pot
-
- echo -n "" >$MSGS_PATH
- echo "% Language: Language Name" >>$MSGS_PATH
- echo "% Author: Translator name and contact method" >>$MSGS_PATH
- echo "" >>$MSGS_PATH
-
- cd $SRC_DIR
- $ERL -pa $EXTRACT_DIR -pa $EBIN_DIR -pa $EJA_SRC_DIR -pa ../include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$POT_PATH.1
- sed -e 's/ \[\]$/ \"\"/g;' $POT_PATH.1 > $POT_PATH.2
-
- #msguniq --sort-by-file $POT_PATH.2 $EJA_MSGS_DIR --output-file=$POT_PATH
- msguniq --sort-by-file $POT_PATH.2 --output-file=$POT_PATH
-
- rm $POT_PATH.*
- rm $MSGS_PATH
-
- # If the project is a specific module, not the main ejabberd
- if [[ $PROJECT != ejabberd ]] ; then
- # Remove from project.pot the strings that are already present in the general ejabberd
- EJABBERD_MSG_FILE=$EJA_MSGS_DIR/es.po # This is just some file with translated strings
- POT_PATH_TEMP=$POT_PATH.temp
- msgattrib --set-obsolete --only-file=$EJABBERD_MSG_FILE -o $POT_PATH_TEMP $POT_PATH
- mv $POT_PATH_TEMP $POT_PATH
- fi
-}
-
-extract_lang_popot2po ()
-{
- LANG_CODE=$1
- PO_PATH=$MSGS_DIR/$LANG_CODE.po
- POT_PATH=$MSGS_DIR/$PROJECT.pot
-
- msgmerge $PO_PATH $POT_PATH >$PO_PATH.translate 2>/dev/null
- mv $PO_PATH.translate $PO_PATH
-}
-
-extract_lang_po2msg ()
-{
- LANG_CODE=$1
- PO_PATH=$LANG_CODE.po
- MS_PATH=$PO_PATH.ms
- MSGID_PATH=$PO_PATH.msgid
- MSGSTR_PATH=$PO_PATH.msgstr
- MSGS_PATH=$LANG_CODE.msg
-
- cd $MSGS_DIR
-
- # Check PO has correct ~
- # Let's convert to C format so we can use msgfmt
- PO_TEMP=$LANG_CODE.po.temp
- cat $PO_PATH | sed 's/%/perc/g' | sed 's/~/%/g' | sed 's/#:.*/#, c-format/g' >$PO_TEMP
- msgfmt $PO_TEMP --check-format
- result=$?
- rm $PO_TEMP
- if [ $result -ne 0 ] ; then
- exit 1
- fi
-
- msgattrib $PO_PATH --translated --no-fuzzy --no-obsolete --no-location --no-wrap | grep "^msg" | tail --lines=+3 >$MS_PATH
- grep "^msgid" $PO_PATH.ms | sed 's/^msgid //g' >$MSGID_PATH
- grep "^msgstr" $PO_PATH.ms | sed 's/^msgstr //g' >$MSGSTR_PATH
- echo "%% -*- coding: latin-1 -*-" >$MSGS_PATH
- paste $MSGID_PATH $MSGSTR_PATH --delimiter=, | awk '{print "{" $0 "}."}' | sort -g >>$MSGS_PATH
-
- rm $MS_PATH
- rm $MSGID_PATH
- rm $MSGSTR_PATH
-}
-
-extract_lang_updateall ()
-{
- echo "Generating POT"
- extract_lang_src2pot
-
- cd $MSGS_DIR
- echo ""
- echo -e "File Missing Language Last translator"
- echo -e "---- ------- -------- ---------------"
- for i in $( ls *.msg ) ; do
- LANG_CODE=${i%.msg}
- echo -n $LANG_CODE | awk '{printf "%-6s", $1 }'
-
- # Convert old MSG file to PO
- PO=$LANG_CODE.po
- [ -f $PO ] || extract_lang_srcmsg2po $LANG_CODE
-
- extract_lang_popot2po $LANG_CODE
- extract_lang_po2msg $LANG_CODE
-
- MISSING=`msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4 }'`
- echo -n " $MISSING"
-
- LANGUAGE=`grep "X-Language:" $PO | sed 's/\"X-Language: //g' | sed 's/\\\\n\"//g' | awk '{printf "%-12s", $1}'`
- echo -n " $LANGUAGE"
-
- LASTAUTH=`grep "Last-Translator" $PO | sed 's/\"Last-Translator: //g' | sed 's/\\\\n\"//g'`
- echo " $LASTAUTH"
- done
- echo ""
- rm messages.mo
-
- cd ..
-}
-
-translation_instructions ()
-{
- echo ""
- echo " A new file has been created for you, with the current, the new and the deprecated strings:"
- echo " $MSGS_PATH2"
- echo ""
- echo " At the end of that file you will find the strings you must update:"
- echo " - Untranslated strings are like this: {"March", ""}."
- echo " To translate the string, add the text inside the commas. Example:"
- echo " {"March", "Marzo"}."
- echo " - Old strings that are not used: "Woowoa""
- echo " Search the entire file for those strings and remove them"
- echo ""
- echo " Once you have translated all the strings and removed all the old ones,"
- echo " rename the file to overwrite the previous one:"
- echo " $MSGS_PATH"
-}
-
-EJA_DIR=`pwd`
-RUN_DIR=`pwd`
-PROJECT=ejabberd
-
-while [ $# -ne 0 ] ; do
- PARAM=$1
- shift
- case $PARAM in
- --) break ;;
- -project)
- PROJECT=$1
- shift
- ;;
- -ejadir)
- EJA_DIR=$1
- shift
- ;;
- -rundir)
- RUN_DIR=$1
- shift
- ;;
- -lang)
- LANGU=$1
- prepare_dirs
- extract_lang $LANGU
- shift
- ;;
- -langall)
- prepare_dirs
- extract_lang_all
- ;;
- -srcmsg2po)
- LANG_CODE=$1
- prepare_dirs
- extract_lang_srcmsg2po $LANG_CODE
- shift
- ;;
- -popot2po)
- LANG_CODE=$1
- prepare_dirs
- extract_lang_popot2po $LANG_CODE
- shift
- ;;
- -src2pot)
- prepare_dirs
- extract_lang_src2pot
- ;;
- -po2msg)
- LANG_CODE=$1
- prepare_dirs
- extract_lang_po2msg $LANG_CODE
- shift
- ;;
- -updateall)
- prepare_dirs
- extract_lang_updateall
- ;;
- *)
- echo "Options:"
- echo " -langall"
- echo " -lang LANGUAGE_FILE"
- echo " -srcmsg2po LANGUAGE Construct .msg file using source code to PO file"
- echo " -src2pot Generate template POT file from source code"
- echo " -popot2po LANGUAGE Update PO file with template POT file"
- echo " -po2msg LANGUAGE Export PO file to MSG file"
- echo " -updateall Generate POT and update all PO"
- echo ""
- echo "Example:"
- echo " ./prepare-translation.sh -lang es.msg"
- exit 0
- ;;
- esac
-done
diff --git a/rebar.config b/rebar.config
index 0744a61c4..d9aaae597 100644
--- a/rebar.config
+++ b/rebar.config
@@ -22,7 +22,7 @@
{tag, {if_version_above, "17", "3.4.2", "3.2.1"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.9"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.10"}}},
- {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.15"}}},
+ {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", "fc3ef32"}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.9"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.23"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "d98be4a3159"}},
diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl
index 7e037da4d..c3c295f66 100644
--- a/src/mod_http_upload.erl
+++ b/src/mod_http_upload.erl
@@ -25,7 +25,7 @@
-module(mod_http_upload).
-author('holger@zedat.fu-berlin.de').
--compile(export_all).
+
-protocol({xep, 363, '0.1'}).
-define(SERVICE_REQUEST_TIMEOUT, 5000). % 5 seconds.
diff --git a/src/xmpp_stream_out.erl b/src/xmpp_stream_out.erl
index af5c67c66..024fdf63b 100644
--- a/src/xmpp_stream_out.erl
+++ b/src/xmpp_stream_out.erl
@@ -51,13 +51,15 @@
-type host_port() :: {inet:hostname(), inet:port_number()}.
-type ip_port() :: {inet:ip_address(), inet:port_number()}.
-type network_error() :: {error, inet:posix() | inet_res:res_error()}.
+-type tls_error_reason() :: inet:posix() | atom() | binary().
+-type socket_error_reason() :: inet:posix() | atom().
-type stop_reason() :: {idna, bad_string} |
{dns, inet:posix() | inet_res:res_error()} |
{stream, reset | {in | out, stream_error()}} |
- {tls, inet:posix() | atom() | binary()} |
+ {tls, tls_error_reason()} |
{pkix, binary()} |
{auth, atom() | binary() | string()} |
- {socket, inet:posix() | atom()} |
+ {socket, socket_error_reason()} |
internal_failure.
-export_type([state/0, stop_reason/0]).
-callback init(list()) -> {ok, state()} | {error, term()} | ignore.
@@ -276,19 +278,20 @@ handle_cast(connect, #{remote_server := RemoteServer,
process_stream_end({idna, bad_string}, State);
ASCIIName ->
case resolve(binary_to_list(ASCIIName), State) of
- {ok, AddrPorts} ->
- case connect(AddrPorts, State) of
+ {{ok, AddrPorts}, Encrypted} ->
+ case connect(AddrPorts, State, Encrypted) of
{ok, Socket, AddrPort} ->
SocketMonitor = SockMod:monitor(Socket),
State1 = State#{ip => AddrPort,
socket => Socket,
+ stream_encrypted => Encrypted,
socket_monitor => SocketMonitor},
State2 = State1#{stream_state => wait_for_stream},
send_header(State2);
- {error, Why} ->
- process_stream_end({socket, Why}, State)
+ {error, {Class, Why}} ->
+ process_stream_end({Class, Why}, State)
end;
- {error, Why} ->
+ {{error, Why}, _} ->
process_stream_end({dns, Why}, State)
end
end);
@@ -578,11 +581,8 @@ process_sasl_mechanisms(Mechs, #{user := User, server := Server} = State) ->
end.
-spec process_starttls(state()) -> state().
-process_starttls(#{sockmod := SockMod, socket := Socket, mod := Mod} = State) ->
- TLSOpts = try Mod:tls_options(State)
- catch _:undef -> []
- end,
- case SockMod:starttls(Socket, [connect|TLSOpts]) of
+process_starttls(#{socket := Socket} = State) ->
+ case starttls(Socket, State) of
{ok, TLSSocket} ->
State1 = State#{socket => TLSSocket,
stream_id => new_id(),
@@ -770,6 +770,19 @@ close_socket(State) ->
State#{stream_timeout => infinity,
stream_state => disconnected}.
+-spec starttls(term(), state()) -> {ok, term()} | {error, tls_error_reason()}.
+starttls(Socket, #{sockmod := SockMod, mod := Mod,
+ xmlns := NS, remote_server := RemoteServer} = State) ->
+ TLSOpts = try Mod:tls_options(State)
+ catch _:undef -> []
+ end,
+ SNI = idna_to_ascii(RemoteServer),
+ ALPN = case NS of
+ ?NS_SERVER -> <<"xmpp-server">>;
+ ?NS_CLIENT -> <<"xmpp-client">>
+ end,
+ SockMod:starttls(Socket, [connect, {sni, SNI}, {alpn, [ALPN]}|TLSOpts]).
+
-spec select_lang(binary(), binary()) -> binary().
select_lang(Lang, <<"">>) -> Lang;
select_lang(_, Lang) -> Lang.
@@ -841,17 +854,17 @@ idna_to_ascii(Host) ->
{error, _} -> ejabberd_idna:domain_utf8_to_ascii(Host)
end.
--spec resolve(string(), state()) -> {ok, [ip_port()]} | network_error().
+-spec resolve(string(), state()) -> {{ok, [ip_port()]} | network_error(), boolean()}.
resolve(Host, State) ->
case srv_lookup(Host, State) of
- {error, _Reason} ->
+ {{error, _Reason}, _} ->
DefaultPort = get_default_port(State),
- a_lookup([{Host, DefaultPort}], State);
- {ok, HostPorts} ->
- a_lookup(HostPorts, State)
+ {a_lookup([{Host, DefaultPort}], State), false};
+ {{ok, HostPorts}, TLS} ->
+ {a_lookup(HostPorts, State), TLS}
end.
--spec srv_lookup(string(), state()) -> {ok, [host_port()]} | network_error().
+-spec srv_lookup(string(), state()) -> {{ok, [host_port()]} | network_error(), boolean()}.
srv_lookup(_Host, #{xmlns := ?NS_COMPONENT}) ->
%% Do not attempt to lookup SRV for component connections
{error, nxdomain};
@@ -867,21 +880,35 @@ srv_lookup(Host, State) ->
{error, _} ->
Timeout = get_dns_timeout(State),
Retries = get_dns_retries(State),
- srv_lookup(Host, Timeout, Retries)
+ case is_starttls_available(State) of
+ true ->
+ case srv_lookup("_xmpps-server._tcp." ++ Host,
+ Timeout, Retries) of
+ {error, _} ->
+ {srv_lookup("_xmpp-server._tcp." ++ Host,
+ Timeout, Retries),
+ false};
+ {ok, Res} ->
+ {{ok, Res}, true}
+ end;
+ false ->
+ {srv_lookup("_xmpp-server._tcp." ++ Host,
+ Timeout, Retries),
+ false}
+ end
end
end.
-spec srv_lookup(string(), timeout(), integer()) ->
{ok, [host_port()]} | network_error().
-srv_lookup(_Host, _Timeout, Retries) when Retries < 1 ->
+srv_lookup(_SRVName, _Timeout, Retries) when Retries < 1 ->
{error, timeout};
-srv_lookup(Host, Timeout, Retries) ->
- SRVName = "_xmpp-server._tcp." ++ Host,
+srv_lookup(SRVName, Timeout, Retries) ->
case inet_res:getbyname(SRVName, srv, Timeout) of
{ok, HostEntry} ->
host_entry_to_host_ports(HostEntry);
{error, timeout} ->
- srv_lookup(Host, Timeout, Retries - 1);
+ srv_lookup(SRVName, Timeout, Retries - 1);
{error, _} = Err ->
Err
end.
@@ -971,10 +998,22 @@ host_entry_to_addr_ports(#hostent{h_addr_list = AddrList}, Port) ->
_ -> {ok, AddrPorts}
end.
--spec connect([ip_port()], state()) -> {ok, term(), ip_port()} | network_error().
-connect(AddrPorts, #{sockmod := SockMod} = State) ->
+-spec connect([ip_port()], state(), boolean()) -> {ok, term(), ip_port()} |
+ {error, {socket, socket_error_reason()}} |
+ {error, {tls, tls_error_reason()}}.
+connect(AddrPorts, #{sockmod := SockMod} = State, TLS) ->
Timeout = get_connect_timeout(State),
- connect(AddrPorts, SockMod, Timeout, {error, nxdomain}).
+ case connect(AddrPorts, SockMod, Timeout, {error, nxdomain}) of
+ {ok, Socket, AddrPort} when TLS ->
+ case starttls(Socket, State) of
+ {ok, TLSSocket} -> {ok, TLSSocket, AddrPort};
+ {error, Why} -> {error, {tls, Why}}
+ end;
+ {ok, _Socket, _AddrPort} = OK ->
+ OK;
+ {error, Why} ->
+ {error, {socket, Why}}
+ end.
-spec connect([ip_port()], module(), timeout(), network_error()) ->
{ok, term(), ip_port()} | network_error().
diff --git a/tools/prepare-tr.sh b/tools/prepare-tr.sh
new file mode 100755
index 000000000..8829b273d
--- /dev/null
+++ b/tools/prepare-tr.sh
@@ -0,0 +1,100 @@
+#!/bin/bash
+
+# Frontend for ejabberd's extract-tr.sh
+
+# How to create template files for a new language:
+# NEWLANG=zh
+# cp priv/msgs/ejabberd.pot priv/msgs/$NEWLANG.po
+# echo \{\"\",\"\"\}. > priv/msgs/$NEWLANG.msg
+# make translations
+
+extract_lang_src2pot ()
+{
+ ./tools/extract-tr.sh ebin/ > priv/msgs/ejabberd.pot
+}
+
+extract_lang_popot2po ()
+{
+ LANG_CODE=$1
+ PO_PATH=$MSGS_DIR/$LANG_CODE.po
+ POT_PATH=$MSGS_DIR/$PROJECT.pot
+
+ msgmerge $PO_PATH $POT_PATH >$PO_PATH.translate 2>/dev/null
+ mv $PO_PATH.translate $PO_PATH
+}
+
+extract_lang_po2msg ()
+{
+ LANG_CODE=$1
+ PO_PATH=$LANG_CODE.po
+ MS_PATH=$PO_PATH.ms
+ MSGID_PATH=$PO_PATH.msgid
+ MSGSTR_PATH=$PO_PATH.msgstr
+ MSGS_PATH=$LANG_CODE.msg
+
+ cd $MSGS_DIR
+
+ # Check PO has correct ~
+ # Let's convert to C format so we can use msgfmt
+ PO_TEMP=$LANG_CODE.po.temp
+ cat $PO_PATH | sed 's/%/perc/g' | sed 's/~/%/g' | sed 's/#:.*/#, c-format/g' >$PO_TEMP
+ msgfmt $PO_TEMP --check-format
+ result=$?
+ rm $PO_TEMP
+ if [ $result -ne 0 ] ; then
+ exit 1
+ fi
+
+ msgattrib $PO_PATH --translated --no-fuzzy --no-obsolete --no-location --no-wrap | grep "^msg" | tail --lines=+3 >$MS_PATH
+ grep "^msgid" $PO_PATH.ms | sed 's/^msgid //g' >$MSGID_PATH
+ grep "^msgstr" $PO_PATH.ms | sed 's/^msgstr //g' >$MSGSTR_PATH
+ echo "%% -*- coding: latin-1 -*-" >$MSGS_PATH
+ paste $MSGID_PATH $MSGSTR_PATH --delimiter=, | awk '{print "{" $0 "}."}' | sort -g >>$MSGS_PATH
+
+ rm $MS_PATH
+ rm $MSGID_PATH
+ rm $MSGSTR_PATH
+}
+
+extract_lang_updateall ()
+{
+ echo ""
+ echo "Generating POT..."
+ extract_lang_src2pot
+
+ cd $MSGS_DIR
+ echo ""
+ echo -e "File Missing (fuzzy) Language Last translator"
+ echo -e "---- ------- ------- -------- ---------------"
+ for i in $( ls *.msg ) ; do
+ LANG_CODE=${i%.msg}
+ echo -n $LANG_CODE | awk '{printf "%-6s", $1 }'
+
+ PO=$LANG_CODE.po
+
+ extract_lang_popot2po $LANG_CODE
+ extract_lang_po2msg $LANG_CODE
+
+ MISSING=`msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4+$7 }'`
+ echo -n " $MISSING"
+
+ FUZZY=`msgfmt --statistics $PO 2>&1 | awk '{printf "%7s", $4 }'`
+ echo -n " $FUZZY"
+
+ LANGUAGE=`grep "X-Language:" $PO | sed 's/\"X-Language: //g' | sed 's/\\\\n\"//g' | awk '{printf "%-12s", $1}'`
+ echo -n " $LANGUAGE"
+
+ LASTAUTH=`grep "Last-Translator" $PO | sed 's/\"Last-Translator: //g' | sed 's/\\\\n\"//g'`
+ echo " $LASTAUTH"
+ done
+ echo ""
+ rm messages.mo
+
+ cd ..
+}
+
+EJA_DIR=`pwd`
+PROJECT=ejabberd
+MSGS_DIR=$EJA_DIR/priv/msgs
+
+extract_lang_updateall