Compare commits

36 Commits

Author SHA1 Message Date
1f5bae0647 Petits détails dans les verifs 2022-12-07 19:59:30 +01:00
7ee84192ae Ajout mail test encodage 2022-12-06 01:51:28 +01:00
a4f926b8b1 Autotest du depollueur 2022-11-30 02:55:56 +01:00
b31762ea43 fix quoteted attach filename 2022-11-27 15:46:15 +01:00
d6e167b83b Attachment mode 2022-11-26 21:55:05 +01:00
9c07023316 change filter limit 2022-11-20 15:10:55 +01:00
4027e16004 update version 2022-11-20 15:09:07 +01:00
8efa333b27 merge develpp 2022-11-20 15:02:29 +01:00
29480b299c fix boundary 2022-11-20 14:55:44 +01:00
6def55c5a7 typo 2022-10-31 19:15:51 +01:00
c448478c39 add lang in a.php 2022-10-31 07:40:19 +01:00
b4ea2185f0 fix synchro plain and html 2022-10-31 07:08:19 +01:00
99e888f5d1 log failed 2022-10-28 15:32:46 +02:00
aa5ae1824d log 2022-04-15 11:11:44 +02:00
8cd159aacb fix TMPFAIL 2022-03-13 19:09:24 +01:00
0d5609501a add admin 2022-03-08 18:06:41 +01:00
48937012ca share lib 2022-03-08 11:11:52 +01:00
9936f8681a update 2022-03-08 09:51:03 +01:00
1ae35941b4 color log / manage "=" in adresses 2022-02-25 08:52:09 +01:00
5d53404735 fix update link 2022-02-20 19:31:35 +01:00
b56089ca6a fix upload archive 2022-02-20 19:08:24 +01:00
2778c10c2e fix update archive 2022-02-20 19:00:13 +01:00
2f713a4e65 update warning 2022-02-19 12:00:16 +01:00
5bc089a94f fix track 2022-02-19 09:49:41 +01:00
a6640e2056 update login 2022-02-19 09:09:45 +01:00
dbe0e45525 update 2022-02-19 08:43:14 +01:00
77c1bb84bd fix setSenderFake 2022-02-18 18:30:30 +01:00
1f2bfec83a fix option 2022-02-17 18:31:38 +01:00
d83b89b624 clean code 2022-02-17 18:13:09 +01:00
bf06a130f6 mv update from script.php to a.php 2022-02-17 17:28:04 +01:00
9c61fd740c size 2022-02-16 16:14:35 +01:00
0d12ce7dcd fix update period 2022-02-15 17:38:01 +01:00
779edcd6dd update jirafeau 2022-02-15 13:30:19 +01:00
7190cf3113 update V2 2022-02-14 17:07:18 +01:00
09bdc4998d token jirafeau 2022-02-12 22:50:10 +01:00
5ec61c7634 fix links 2022-02-11 01:01:24 +01:00
23 changed files with 98003 additions and 428 deletions

View File

@ -58,12 +58,12 @@ JIR_OUT = $(patsubst %, $(OUT_DIR)/%, $(JIR_PRG))
## FLAGS ###############################
DFLAGS = -O2 -DDISABLE_LOG
#DFLAGS = -g -Wall
#DFLAGS = -O2 -DDISABLE_LOG
DFLAGS = -g -Wall
IFLAGS = $(DFLAGS) -MMD -I$(HPP_DIR) -std=c++11
LFLAGS = -L$(LIB_DIR) -Bstatic -lstdc++ -lcurl -lcrypto -lboost_system -lboost_program_options -lboost_filesystem
LFLAGS = -L$(LIB_DIR) -lboost_system -lboost_program_options -lboost_filesystem -lcurl -lcrypto -lstdc++
CC = g++
## RULES ###############################
@ -71,7 +71,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/*/%.cpp
$(CC) $< $(IFLAGS) -cpp -c -o $@
## ENTRIES #############################
all: init eMailShrinker jirafeauAPI
all: init eMailShrinker jirafeauAPI doc
eMailShrinker: $(KAZ_OUT)
@ -83,6 +83,9 @@ jirafeauAPI: $(JIR_OUT)
$(JIR_OUT): $(JIR_OBJ)
$(CC) $(JIR_OBJ) $(IFLAGS) -cpp -L$(LIB_DIR) $(LFLAGS) -o $@
doc:
doxygen src/Doxyfile
init:
mkdir -p $(OUT_DIR) $(OBJ_DIR) $(LIB_DIR)

View File

@ -33,7 +33,7 @@ depollueur/
## Compilation
```bash
sudo apt-get install --fix-missing build-essential make g++ libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libcurl4-gnutls-dev libssl-dev
sudo apt-get install --fix-missing build-essential make g++ libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libcurl4-gnutls-dev libssl-dev doxygen
git clone https://git.kaz.bzh/KAZ/depollueur.git
# or for contributors :
@ -41,3 +41,14 @@ git clone https://git.kaz.bzh/KAZ/depollueur.git
make -j $(nproc)
```
##Astuces
Pour la mise au point dans Kaz, il faut bloquer la mise à jour automatique avec :
``` bash
touch /kaz/git/depollueur/dontupdage
/kaz/bin/container.sh stop jirafeau postfix; docker system prune; /kaz/bin/install.sh jirafeau postfix
```

2658
src/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -101,7 +101,8 @@ if (!empty($delete_code) && $delete_code == $link['link_code']) {
<?php echo t('USING_SERVICE'). ' <a href="tos.php" target="_blank" rel="noopener noreferrer">' . t('TOS') . '</a>.' ?>
</td></tr>
<tr><td>
<input type="submit" id="submit_delete" value="<?php echo t('DELETE'); ?>" <?php $action_delete="'f.php?h=' . $link_name . '&amp;d=' . $delete_code'; document.getElementById('submit_delete').submit ();"; ?>
<input type="submit" id="submit_delete" value="<?php echo t('DELETE'); ?>"
<?php $action_delete="'f.php?h=' . $link_name . '&amp;d=' . $delete_code'; document.getElementById('submit_delete').submit ();"; ?>
onclick="document.getElementById('submit_delete_post').action='<?php echo $action_delete; ?>" />
</td></tr>
</table>
@ -288,3 +289,4 @@ if ($link['onetime'] == 'O') {
exit;
?>

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
##########################################################################
# Copyright KAZ 2021 #
# #
@ -41,6 +41,10 @@
# le roriétaire du script
##########################################################################
DEFAULT_MODE="footer"
DEFAULT_PERIOD="month"
DEFAULT_TRACK=""
cd $(dirname $0)
DOMAINNAME=$(cat domainname)
# Exit codes from <sysexits.h>
@ -48,11 +52,12 @@ EX_TEMPFAIL=75
EX_UNAVAILABLE=69
EX_TOO_LARGE=552
INSPECT_DIR=/var/spool/filter
FIC_LOG=/var/log/mail/filter.log
DIR_LOG=/var/log/mail
FIC_LOG=${DIR_LOG}/filter.log
SENDMAIL="/usr/sbin/sendmail -G -i"
MAILS=/tmp/FILTER
MAX_KEEP_IN_MAIL=24ki
MAX_UPLOAD_SIZE=100Mi
MAX_KEEP_IN_MAIL=5ki
MAX_UPLOAD_SIZE=1Gi
SHRINK_CMD=/home/filter/eMailShrinker
JIRAFEAU_CMD=/home/filter/jirafeauAPI
JIRAFEAU_URL=https://depot.${DOMAINNAME:-"kaz.bzh"}
@ -60,23 +65,75 @@ JIRAFEAU_LOCAL=http://depot
JIRAFEAU_TIME=month
MD5_CMD=/usr/bin/md5sum
DISCLAMER_CMD=altermime
MAX_FINAL_SIZE=204800 # 200ki
MAX_FINAL_SIZE=2097152 # 2Mi
ARCHIVE_TITLE="archive_content"
ARCHIVE_MIME="text/kaz_email_archive"
KEEP_FAILED=true
DEBUG=
#################### FONCTIONS ############################################
BOLD=''
RED=''
GREEN=''
YELLOW=''
BLUE=''
MAGENTA=''
CYAN=''
NC='' # No Color
NL='
'
#--------------------- Fichier de LOG -------------------
LOG_FIC () {
echo "$(date +%d-%m-%Y-%H-%M-%S) : $*" >> "${FIC_LOG}"
echo "${BLUE}$(date +%d-%m-%Y-%H-%M-%S)${NC} : $*" >> "${FIC_LOG}"
}
quitFilter () {
LOG_FIC "${GREEN}######################################## filter stop${NC}"
exit $1
}
keepFailed () {
[ -z "${KEEP_FAILED}" ] && return
mkdir -p "${DIR_LOG}/pb/"
cp "$1" "${DIR_LOG}/pb/"
}
#################### MAIN #################################################
LOG_FIC "------------------------------------------------------"
LOG_FIC "--------------- debut de programme -------------------"
echo "${NL}" >> "${FIC_LOG}"
LOG_FIC "${GREEN}######################################## filter start${NC}"
mkdir -p "${MAILS}" || { LOG_FIC "impossible de creer ce dossier"; exit "${EX_UNAVAILABLE}"; }
if ! mkdir -p "${MAILS}"; then
LOG_FIC "${RED}Can't mkdir ${MAILS} ${NC}"
quitFilter "${EX_UNAVAILABLE}"
fi
MAIL_SOURCE=$(echo $@ | awk 'BEGIN{FS=" "} {print $2}')
DATE_TEMPS=$(date "+%Y-%m-%d-%H:%M:%S")
REP_PIECE_JOINTE=$(echo "${MAILS}/${DATE_TEMPS}_${MAIL_SOURCE}_$$")
cd "${INSPECT_DIR}" || { echo "${INSPECT_DIR} does not exist"; exit "${EX_TEMPFAIL}"; }
REP_PIECE_JOINTE="${MAILS}/${DATE_TEMPS}_${MAIL_SOURCE}_$$"
MODE=$(curl "${JIRAFEAU_LOCAL}/a.php?m=${MAIL_SOURCE}" 2>/dev/null )
[[ "${MODE}" =~ ^(footer|attachment|both)$ ]] || MODE="${DEFAULT_MODE}"
TRACK=$(curl "${JIRAFEAU_LOCAL}/a.php?r=${MAIL_SOURCE}" 2>/dev/null )
[[ "${TRACK}" =~ ^(|0|1|false|true|FALSE|TRUE|on|off)$ ]] || TRACK="${DEFAULT_TRACK}"
PERIOD=$(curl "${JIRAFEAU_LOCAL}/a.php?p=${MAIL_SOURCE}" 2>/dev/null )
[[ "${PERIOD}" =~ ^(minute|hour|day|week|month|quarter)$ ]] || PERIOD="${DEFAULT_PERIOD}"
if [ -n "$(echo "${PERIOD}" | grep -e minute -e hour -e day -e week -e month -e quarter 2>/dev/null)" ]; then
JIRAFEAU_TIME="${PERIOD}"
fi
LOG_FIC "\n" \
" MAIL_SOURCE : ${YELLOW}${MAIL_SOURCE}${NC}\n" \
" DATE_TEMPS : ${YELLOW}${DATE_TEMPS=}${NC}\n" \
" TRACK : ${YELLOW}${TRACK}${NC}\n" \
" PERIOD : ${YELLOW}${PERIOD}${NC}\n" \
" JIRAFEAU_TIME: ${YELLOW}${JIRAFEAU_TIME}${NC}"
if ! cd "${INSPECT_DIR}"; then
echo "${INSPECT_DIR} does not exist"
quitFilter "${EX_TEMPFAIL}"
fi
# lien renvoyé par le téléverssement
ONE_LINK="${REP_PIECE_JOINTE}/one.txt"
@ -84,129 +141,145 @@ ONE_LINK="${REP_PIECE_JOINTE}/one.txt"
OLD_LINKS="${REP_PIECE_JOINTE}/url-to-refresh.txt"
# contenu de l'archive
ARCHIVE_CONTENT="${REP_PIECE_JOINTE}/archive-content.txt"
# create if error
JIRAFEAU_ERROR="${REP_PIECE_JOINTE}/jirafeau-error.txt"
# Clean up when done or when aborting.
trap "rm -rf in.$$ in.$$.altered ${REP_PIECE_JOINTE}" 0 1 2 3 15
[ -z "${DEBUG}" ] && trap "rm -rf in.$$ in.$$.altered ${REP_PIECE_JOINTE}" 0 1 2 3 15
cat > "in.$$" || { LOG_FIC "Cannot save mail to file"; exit "${EX_TEMPFAIL}"; }
# XXX trace
# cp "${INSPECT_DIR}/in.$$" "${INSPECT_DIR}/in.$$.bak"
if ! cat > "in.$$"; then
LOG_FIC "${RED}Cannot save mail to file${NC}"
quitFilter "${EX_TEMPFAIL}"
fi
LOG_FIC "\n" \
" size: ${YELLOW}$(wc -c < "${INSPECT_DIR}/in.$$")${NC}"
[ -n "${DEBUG}" ] && (mkdir -p "${DIR_LOG}/pb/" ; cp "${INSPECT_DIR}/in.$$" "${DIR_LOG}/pb/in.$$.orig")
mkdir -p "${REP_PIECE_JOINTE}/"
>"${OLD_LINKS}"
>"${ARCHIVE_CONTENT}"
# Etape de rafraichissement des anciens fichiers inclus
cat > "${ARCHIVE_CONTENT}" <<EOF
src: ${MAIL_SOURCE}
time: ${DATE_TEMPS}
EOF
LOG_FIC "${SHRINK_CMD} -u \"${INSPECT_DIR}/in.$$\" 2>> \"${FIC_LOG}\" > \"${OLD_LINKS}\""
echo "time: ${DATE_TEMPS}\nid: $(date +%s)" > "${ARCHIVE_CONTENT}"
[ -n "${TRACK}" ] && echo "sender: ${MAIL_SOURCE}" >> "${ARCHIVE_CONTENT}"
LOG_FIC "${CYAN}${SHRINK_CMD} -u \"${INSPECT_DIR}/in.$$\" 2>> \"${FIC_LOG}\" > \"${OLD_LINKS}\"${NC}"
"${SHRINK_CMD}" -u "${INSPECT_DIR}/in.$$" 2>> "${FIC_LOG}" > "${OLD_LINKS}"
cat "${OLD_LINKS}" | grep "${JIRAFEAU_URL}" | while read REMOTE_LINK
do
cat "${OLD_LINKS}" | grep "${JIRAFEAU_URL}" | while read REMOTE_LINK; do
REMOTE_REF=$(echo "${REMOTE_LINK}" | sed -e 's/.*h=\([^&]*\).*/\1/' -e 's/.*http.*//')
[ -z "${REMOTE_REF}" ] && continue
REMOTE_KEY=$(echo "${REMOTE_LINK}" | grep "k=" | sed 's%.*k=\([^&]*\).*%\1%')
# update periode for download
LOG_FIC " - \"${JIRAFEAU_CMD}\" -f \"${JIRAFEAU_LOCAL}\" -t \"${JIRAFEAU_TIME}\" update \"${REMOTE_REF}\" 2>&1 >> \"${FIC_LOG}\""
LOG_FIC " - ${CYAN}\"${JIRAFEAU_CMD}\" -f \"${JIRAFEAU_LOCAL}\" -t \"${JIRAFEAU_TIME}\" update \"${REMOTE_REF}\" 2>&1 >> \"${FIC_LOG}\"${NC}"
"${JIRAFEAU_CMD}" -f "${JIRAFEAU_LOCAL}" -t "${JIRAFEAU_TIME}" update "${REMOTE_REF}" 2>&1 >> "${FIC_LOG}"
echo "old: ${REMOTE_REF} ${REMOTE_KEY}" >> "${ARCHIVE_CONTENT}"
done
LOG_FIC " - archive starts with: $(cat ${ARCHIVE_CONTENT})"
LOG_FIC " - archive starts with: ${NL}${YELLOW}$(cat ${ARCHIVE_CONTENT})${NC}"
# Etape extraction des pieces jointes
LOG_FIC "${SHRINK_CMD} -s ${MAX_KEEP_IN_MAIL} -d ${REP_PIECE_JOINTE} ${INSPECT_DIR}/in.$$"
LOG_FIC "${CYAN}${SHRINK_CMD} -s ${MAX_KEEP_IN_MAIL} -d ${REP_PIECE_JOINTE} ${INSPECT_DIR}/in.$$ ${NC}"
"${SHRINK_CMD}" -s "${MAX_KEEP_IN_MAIL}" -d "${REP_PIECE_JOINTE}" "${INSPECT_DIR}/in.$$" 2>> "${FIC_LOG}" | {
while read ATTACH_TMP_NAME
do
if [ -d "${ATTACH_TMP_NAME}" ]
then
while read ATTACH_TMP_NAME; do
if [ -d "${ATTACH_TMP_NAME}" ]; then
ATTACH_MEDIA="${ATTACH_TMP_NAME}/media"
ATTACH_NAME=$(grep "^Name: " "${ATTACH_TMP_NAME}/meta" | cut -c 7- )
ATTACH_CONTENT_TYPE=$(grep "^Content-Type: " "${ATTACH_TMP_NAME}/meta" | cut -c 15- )
else
LOG_FIC " - ${RED}no ATTACH_TMP_NAME (${ATTACH_TMP_NAME}) ${NC}"
# XXX error
continue
fi
# Etape de televersement des pieces jointes
PASSWORD=$(apg -n 1 -m 12)
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
LOG_FIC " - \"${JIRAFEAU_CMD}\" -f \"${JIRAFEAU_LOCAL}\" -s \"${MAX_UPLOAD_SIZE}\" -c \"${ATTACH_CONTENT_TYPE}\" -n \"${ATTACH_NAME}\" send \"${ATTACH_MEDIA}\" \"${PASSWORD}\" 2>> \"${FIC_LOG}\" > \"${ONE_LINK}\""
"${JIRAFEAU_CMD}" -f "${JIRAFEAU_LOCAL}" -s "${MAX_UPLOAD_SIZE}" -c "${ATTACH_CONTENT_TYPE}" -n "${ATTACH_NAME}" send "${ATTACH_MEDIA}" "${PASSWORD}" 2>> "${FIC_LOG}" > "${ONE_LINK}"
LOG_FIC " - ${CYAN}\"${JIRAFEAU_CMD}\" -f \"${JIRAFEAU_LOCAL}\" -t \"${JIRAFEAU_TIME}\" -s \"${MAX_UPLOAD_SIZE}\" -c \"${ATTACH_CONTENT_TYPE}\" -n \"${ATTACH_NAME}\" send \"${ATTACH_MEDIA}\" \"${PASSWORD}\" 2>> \"${FIC_LOG}\" > \"${ONE_LINK}\"${NC}"
"${JIRAFEAU_CMD}" -f "${JIRAFEAU_LOCAL}" -t "${JIRAFEAU_TIME}" -s "${MAX_UPLOAD_SIZE}" -c "${ATTACH_CONTENT_TYPE}" -n "${ATTACH_NAME}" send "${ATTACH_MEDIA}" "${PASSWORD}" 2>> "${FIC_LOG}" > "${ONE_LINK}"
cat "${ONE_LINK}" | {
read JIR_TOKEN
read JIR_CODE
LOG_FIC " - Jirafeau retourne ${JIR_TOKEN} et ${JIR_CODE}"
LOG_FIC " - return code ${YELLOW}${JIR_TOKEN}${NC} / ${YELLOW}${JIR_CODE}${NC}"
case "${JIR_TOKEN}" in
"" | no | *Error* | \<* )
LOG_FIC " - impossible de televerser ${ATTACH_TMP_FILE} (${JIR_TOKEN}), il ne sera pas remplace dans le message"
echo "new:"
LOG_FIC " - ${RED}Can't upload <${ATTACH_NAME}> <${ATTACH_CONTENT_TYPE}> <$(wc -c < "${ATTACH_MEDIA}")> (${JIR_TOKEN}) <in.$$.bak>. It will be not change in e-mail.${NC}"
echo "url:"
keepFailed "${INSPECT_DIR}/in.$$"
echo "UPLOAD_FAIL" >> "${JIRAFEAU_ERROR}"
;;
* )
LOG_FIC " - substitution par ${JIRAFEAU_URL}/f.php?d=1&h=${JIR_TOKEN}&k=${PASSWORD_MD5}"
LOG_FIC " - change by link ${YELLOW}${JIRAFEAU_URL}/f.php?d=1&h=${JIR_TOKEN}&k=${PASSWORD_MD5}${NC}"
echo "url: ${JIRAFEAU_URL}/f.php?d=1&h=${JIR_TOKEN}&k=${PASSWORD_MD5}"
echo "new: ${JIR_TOKEN} ${PASSWORD_MD5}" >> "${ARCHIVE_CONTENT}"
;;
esac
}
LOG_FIC " - supprimer l'extraction ${ATTACH_TMP_FILE}"
rm -f "${ATTACH_TMP_FILE}"
done
# Création de l'archive
if [ "$(wc -l < "${ARCHIVE_CONTENT}")" -ge 4 ]; then
NB_ATTACH=$(grep -e "^old: " -e "^new: " "${ARCHIVE_CONTENT}" | wc -l)
if [ \( -n "${TRACK}" -a "${NB_ATTACH}" -gt 0 \) -o "${NB_ATTACH}" -gt 1 ]; then
PASSWORD=$(apg -n 1 -m 12)
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
LOG_FIC " - \"${JIRAFEAU_CMD}\" -f \"${JIRAFEAU_LOCAL}\" -s \"${MAX_UPLOAD_SIZE}\" -c \"text/plain\" -n \"archive_content\" send \"${ARCHIVE_CONTENT}\" \"${PASSWORD}\" 2>> \"${FIC_LOG}\" > \"${ONE_LINK}\""
"${JIRAFEAU_CMD}" -f "${JIRAFEAU_LOCAL}" -s "${MAX_UPLOAD_SIZE}" -c "text/plain" -n "archive_content" send "${ARCHIVE_CONTENT}" "${PASSWORD}" 2>> "${FIC_LOG}" > "${ONE_LINK}"
LOG_FIC " - ${MAGENTA}upload archive${NC}"
LOG_FIC " - ${CYAN}\"${JIRAFEAU_CMD}\" -f \"${JIRAFEAU_LOCAL}\" -t \"${JIRAFEAU_TIME}\" -s \"${MAX_UPLOAD_SIZE}\" -c \"${ARCHIVE_MIME}\" -n \"${ARCHIVE_TITLE}\" send \"${ARCHIVE_CONTENT}\" \"${PASSWORD}\" 2>> \"${FIC_LOG}\" > \"${ONE_LINK}\"${NC}"
"${JIRAFEAU_CMD}" -f "${JIRAFEAU_LOCAL}" -t "${JIRAFEAU_TIME}" -s "${MAX_UPLOAD_SIZE}" -c "${ARCHIVE_MIME}" -n "${ARCHIVE_TITLE}" send "${ARCHIVE_CONTENT}" "${PASSWORD}" 2>> "${FIC_LOG}" > "${ONE_LINK}"
fi
LOG_FIC " - final archive content: ${NL}${YELLOW}$(cat ${ARCHIVE_CONTENT})${NC}"
if [ "${NB_ATTACH}" -gt 1 ]; then
cat "${ONE_LINK}" | {
read JIR_TOKEN
read JIR_CODE
LOG_FIC " - Jirafeau retourne ${JIR_TOKEN} et ${JIR_CODE}"
LOG_FIC " - return code ${YELLOW}${JIR_TOKEN}${NC} / ${YELLOW}${JIR_CODE}${NC}"
case "${JIR_TOKEN}" in
"" | no | *Error* | \<* )
LOG_FIC " - impossible de televerser l'archive (${JIR_TOKEN}), il ne sera pas remplace dans le message"
LOG_FIC " - ${RED}can't upload archive (${JIR_TOKEN}) <in.$$.bak>, substitution couldn't be done${NC}"
echo "arch: bad"
keepFailed "${INSPECT_DIR}/in.$$"
echo "ARCHIVE_FAIL" >> "${JIRAFEAU_ERROR}"
;;
* )
LOG_FIC " - ajoute de l'archive ${JIRAFEAU_URL}/a.php?g=${JIR_TOKEN}~${PASSWORD_MD5}"
LOG_FIC " - add archive ${YELLOW}${JIRAFEAU_URL}/a.php?g=${JIR_TOKEN}~${PASSWORD_MD5}${NC}"
echo "arch: ${JIRAFEAU_URL}/a.php?g=${JIR_TOKEN}~${PASSWORD_MD5}"
;;
esac
}
else
LOG_FIC " - pas d'archive (moins de 2 PJ)"
LOG_FIC " - no archive (less than 2 attach file)"
echo "arch: none"
fi
# Etape de substitution
LOG_FIC "${SHRINK_CMD} -s \"${MAX_KEEP_IN_MAIL}\" \"${INSPECT_DIR}/in.$$\" \"${INSPECT_DIR}/in.$$.altered\" 2>> \"${FIC_LOG}\""
} | "${SHRINK_CMD}" -s "${MAX_KEEP_IN_MAIL}" "${INSPECT_DIR}/in.$$" "${INSPECT_DIR}/in.$$.altered" 2>> "${FIC_LOG}"
LOG_FIC "${CYAN}${SHRINK_CMD} -m \"${MODE}\" -s \"${MAX_KEEP_IN_MAIL}\" \"${INSPECT_DIR}/in.$$\" \"${INSPECT_DIR}/in.$$.altered\" 2>> \"${FIC_LOG}\"${NC}"
} | "${SHRINK_CMD}" -m "${MODE}" -s "${MAX_KEEP_IN_MAIL}" "${INSPECT_DIR}/in.$$" "${INSPECT_DIR}/in.$$.altered" 2>> "${FIC_LOG}"
# XXX trace
# cp "${INSPECT_DIR}/in.$$" "${INSPECT_DIR}/in.$$.altered" /var/mail/tmp/
[ -n "${DEBUG}" ] && (mkdir -p "${DIR_LOG}/pb/" ; cp "${INSPECT_DIR}/in.$$.altered" "${DIR_LOG}/pb/in.$$.altered")
if [ -s "${JIRAFEAU_ERROR}" ]; then
LOG_FIC " - ${RED}upload fail${NC}"
quitFilter "${EX_TEMPFAIL}"
fi
# Etape choix de modification du message d'origine
if [ "$(wc -l < "${ARCHIVE_CONTENT}")" -ge 3 ]; then
# verification de taille finale
actualSize=$(wc -c < "${INSPECT_DIR}/in.$$.altered")
if [ ${actualSize} -ge $MAX_FINAL_SIZE ]; then
LOG_FIC " - message trop gros apres regime ${INSPECT_DIR}/in.$$.altered (${actualSize})"
exit "${EX_TOO_LARGE}";
LOG_FIC " - ${RED}too big even after diet ${INSPECT_DIR}/in.$$.altered (${actualSize})${NC}"
keepFailed "${INSPECT_DIR}/in.$$"
quitFilter "${EX_TOO_LARGE}"
fi
LOG_FIC " - envoi de la commande : ${SENDMAIL} $@ ${INSPECT_DIR}/in.$$.altered"
LOG_FIC " - ${GREEN}send with : ${SENDMAIL} $@ ${INSPECT_DIR}/in.$$.altered ${NC}"
${SENDMAIL} "$@" < "${INSPECT_DIR}/in.$$.altered"
else
# verification de taille finale
actualSize=$(wc -c < "${INSPECT_DIR}/in.$$")
if [ ${actualSize} -ge $MAX_FINAL_SIZE ]; then
LOG_FIC " - message trop gros sans regime ${INSPECT_DIR}/in.$$ (${actualSize})"
exit "${EX_TOO_LARGE}";
LOG_FIC " - ${RED}too big without diet ${INSPECT_DIR}/in.$$ (${actualSize}) ${NC}"
keepFailed "${INSPECT_DIR}/in.$$"
quitFilter "${EX_TOO_LARGE}"
fi
LOG_FIC " - pas de piece jointe"
LOG_FIC " - ${GREEN}send without attach file${NC}"
${SENDMAIL} "$@" < "in.$$"
fi
exit 0
quitFilter 0
##########################################################################

136
src/bash/filterTest.sh Normal file
View File

@ -0,0 +1,136 @@
#!/bin/bash
PRG=$(basename $0)
ATTACH_MODE="-m BOTH"
BOLD=''
RED=''
GREEN=''
YELLOW=''
BLUE=''
MAGENTA=''
CYAN=''
NC='' # No Color
NL='
'
TTY=$(tty)
LOG () {
echo "$1" >> "${TTY}"
}
usage () {
echo "Usage: ${PRG} mbox"
exit 1
}
[ "$#" -eq 1 ] || usage
mbox=$(realpath $1)
cd $(dirname $0)
DOMAINNAME="$(cat domainname)"
JIRAFEAU_URL="https://depot.${DOMAINNAME}"
JIRAFEAU_LOCAL="${JIRAFEAU_URL}"
cd ../..
mkdir -p tmp
rm -fr tmp/PJ-name.txt tmp/PJ-Keys.txt tmp/PJ tmp/archive-content.txt tmp/url-to-refresh.txt tmp/new-mbox
echo -e "time: $(date "+%Y-%m-%d-%H:%M:%S")\nid: $(date +%s)" > "tmp/archive-content.txt"
LOG " - ${BLUE}mbox: ${mbox}${NC}"
build/out/eMailShrinker -l "${mbox}"
LOG
build/out/eMailShrinker -u "${mbox}" > "tmp/url-to-refresh.txt" 2>> "${TTY}"
cat "tmp/url-to-refresh.txt" | grep "${JIRAFEAU_URL}" | while read REMOTE_LINK; do
REMOTE_REF=$(echo "${REMOTE_LINK}" | sed -e 's/.*h=\([^&]*\).*/\1/' -e 's/.*http.*//')
[ -z "${REMOTE_REF}" ] && continue
LOG " - ${BLUE}update ${REMOTE_REF}${NC}"
build/out/jirafeauAPI -f "${JIRAFEAU_LOCAL}" -t "month" update "${REMOTE_REF}" 2>> "${TTY}"
LOG
echo "old: ${REMOTE_REF} ${REMOTE_KEY}" >> "tmp/archive-content.txt"
done
build/out/eMailShrinker -s "5ki" -d tmp/PJ "${mbox}" > "tmp/PJ-name.txt"
LOG " - ${BLUE}PJ-name: ${NC}"
cat tmp/PJ-name.txt
LOG
cat "tmp/PJ-name.txt" | {
while read ATTACH_TMP_NAME; do
LOG " - ${BLUE}find ATTACH_TMP_NAME: (${ATTACH_TMP_NAME}) ${NC}"
if [ -d "${ATTACH_TMP_NAME}" ]; then
ATTACH_MEDIA="${ATTACH_TMP_NAME}/media"
ATTACH_NAME=$(grep "^Name: " "${ATTACH_TMP_NAME}/meta" | cut -c 7- )
ATTACH_CONTENT_TYPE=$(grep "^Content-Type: " "${ATTACH_TMP_NAME}/meta" | cut -c 15- )
else
LOG " - ${RED}no ATTACH_TMP_NAME: ${ATTACH_TMP_NAME}${NC}"
# XXX error
continue
fi
LOG " - ${BLUE}find ${ATTACH_NAME} / (${ATTACH_CONTENT_TYPE}) / ${ATTACH_MEDIA} ${NC}"
PASSWORD=$(apg -n 1 -m 12)
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
build/out/jirafeauAPI -f "${JIRAFEAU_LOCAL}" -t "month" -s "1Gi" -c "${ATTACH_CONTENT_TYPE}" -n "${ATTACH_NAME}" send "${ATTACH_MEDIA}" "${PASSWORD}" 2>> "${TTY}" > "tmp/one.txt"
cat "tmp/one.txt" | {
read JIR_TOKEN
read JIR_CODE
case "${JIR_TOKEN}" in
"" | no | *Error* | \<* )
LOG " - ${RED}can't upload ${ATTACH_MEDIA} <${JIR_TOKEN}> <${JIR_CODE}>${NC}"
cat "tmp/one.txt" >> "${TTY}"
echo "url:"
;;
* )
LOG " - ${GREEN} upload ${ATTACH_MEDIA}${NC}"
echo "url: ${JIRAFEAU_URL}/f.php?d=1&h=${JIR_TOKEN}&k=${PASSWORD_MD5}"
echo "new: ${JIR_TOKEN} ${PASSWORD_MD5}" >> "tmp/archive-content.txt"
;;
esac
}
done
NB_ATTACH=$(grep -e "^old: " -e "^new: " "tmp/archive-content.txt" | wc -l)
if [ "${NB_ATTACH}" -gt 1 ]; then
PASSWORD=$(apg -n 1 -m 12)
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
build/out/jirafeauAPI -f "${JIRAFEAU_LOCAL}" -t "month" -s "1Gi" -c "text/kaz_email_archive" -n "archive_content" send "tmp/archive-content.txt" "${PASSWORD}" > "tmp/one.txt" 2>> "${TTY}"
cat "tmp/one.txt" | {
read JIR_TOKEN
read JIR_CODE
case "${JIR_TOKEN}" in
"" | no | *Error* | \<* )
LOG " - ${RED}can't upload tmp/archive-content.txt${NC}"
echo "arch: bad"
;;
* )
LOG " - ${GREEN} upload archive-content.txt${NC}"
echo "arch: ${JIRAFEAU_URL}/a.php?g=${JIR_TOKEN}~${PASSWORD_MD5}"
;;
esac
}
else
LOG " - ${GREEN} no archive${NC}"
echo "arch: none"
fi
} > "tmp/PJ-Keys.txt"
LOG " - ${BLUE}PJ-Keys: ${NC}"
cat tmp/PJ-Keys.txt
LOG
LOG " - ${GREEN}ATTACH_MODE: ${ATTACH_MODE}${NC}"
cat "tmp/PJ-Keys.txt" | build/out/eMailShrinker ${ATTACH_MODE} -s "5ki" "${mbox}" "tmp/new-mbox" 2>> "${TTY}"
LOG " - ${BLUE}new-mbox:${NC}"
build/out/eMailShrinker -l "tmp/new-mbox" 2>> "${TTY}"

View File

@ -61,11 +61,19 @@ const string Attachment::PLAIN ("plain");
const string Attachment::HTML ("html");
const string Attachment::RELATED ("related");
const string Attachment::ALTERNATIVE ("alternative");
const string Attachment::KAZ_ATTACH_NAME (".---KazAttachment---.html");
const regex Attachment::nameCharsetRegEx (".*name\\*=(.*)");
const regex Attachment::nameRegEx (".*name=\"([^\"]*)\".*");
const regex Attachment::boundaryRegEx (".*boundary=\"?([^\" ]*)\"?.*");
const regex Attachment::nameRegEx (".*name=\\s*\"?(.*)\"?\\s*;?\\s*");
// boundary="----=_Part_796779_1154936629.1668080348646"
// boundary="------------040709000505010508040808"
// boundary="----------=_1668606031-941125-91"
// boundary="_004_PAVPR10MB6792713B313048E3A259B215B2079PAVPR10MB6792EURP_";
// boundary="_000_PAVPR10MB6792713B313048E3A259B215B2079PAVPR10MB6792EURP_"
// boundary=--boundary_1351_64006126-2b0e-4a3b-98ac-4797d1634188
// boundary=--boundary_1352_7e294c9a-cfab-44a0-bfb3-7310380ac7cb;
const regex Attachment::boundaryRegEx (".*boundary=\"?([^\"; ]*)\"?;?.*");
const regex Attachment::cidDefRegEx (".*<([^>]*)>.*");
const regex Attachment::textRegEx (".*text/("+PLAIN+"|"+HTML+").*");
const regex Attachment::multiRegEx ("\\s*multipart/(mixed|"+RELATED+"|"+ALTERNATIVE+").*");
@ -266,6 +274,7 @@ Attachment::Attachment (ifstream &mbox, const int &level, const streamoff beginI
toExtract (false),
toUpdate (false),
toDisclaim (false),
isKazAttachment (false),
boundaryMiddleSize (0) {
DEF_LOG ("Attachment::Attachment", "curPos: " << curPos << " level: " << level);
readMime (mbox, curPos);
@ -354,7 +363,11 @@ Attachment::nextBondary (ifstream &mbox, streamoff &curPos) {
++it)
if (couple.find (*it) != string::npos) {
LOG ("find: "+ *it);
LOG ("size: " << subAttachements.size ());
if (subAttachements.size ())
subAttachements.back ().toUpdate = true;
else
LOG_BUG (true, continue, "eMailShrinker: bug A10: boundary format ? " << *this);
}
prev = clearLine;
continue;
@ -406,6 +419,9 @@ Attachment::markSignificant (const string &parentMultiProp, const streamoff &min
for (Attachment &sub : subAttachements)
cantBeExtract |= sub.markSignificant (multiProp, minAttachSize, mbox, allMarkedPtrs);
if (getProp (contentTypeToken, textRegEx) == HTML) {
if (KAZ_ATTACH_NAME == getAttachName ()) {
isKazAttachment = true;
} else {
string content = getContent (mbox);
vector<string> imgs;
getSection (content, IMG_BEGIN, IMG_END, imgs);
@ -413,10 +429,11 @@ Attachment::markSignificant (const string &parentMultiProp, const streamoff &min
if (embeddedData.size ())
toUpdate = true;
}
}
cantBeExtract |= toUpdate;
if (boundary.empty () && getSize () >= minAttachSize && !cantBeExtract)
cantBeExtract = toExtract = true; // XXX cantBeExtract ?
if (toExtract || toUpdate || toDisclaim)
if (toExtract || toUpdate || toDisclaim || isKazAttachment)
allMarkedPtrs.push_back (this);
return cantBeExtract;
}
@ -489,7 +506,7 @@ kaz::operator << (ostream& os, const Attachment& attachment) {
if (prop.length ())
prop = " ["+prop+"]";
os << setw ((attachment.level % 20)*2) << "" << setw (10) << SizeArg (attachment.getSize ()) << " " << attachment.getContentType ()
os << ("****************************************"+40-(attachment.level % 20)*2) << setw (10) << SizeArg (attachment.getSize ()) << " " << attachment.getContentType ()
<< prop << (attachment.cid.length () ? " id: "+attachment.cid : "")
<< (attachment.boundary.length () ? " boundary: "+attachment.boundary : "")
<< " (" << attachment.beginPos << " / " << attachment.contentPos << " / " << attachment.endPos << ") " << endl;

View File

@ -32,14 +32,18 @@
// knowledge of the CeCILL-B license and that you accept its terms. //
////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <math.h>
#include <algorithm>
#include <regex>
#include <set>
#include <unistd.h>
#include <vector>
#include <boost/assign.hpp>
#include <boost/algorithm/string.hpp>
#include "kazDebug.hpp"
#include "kazMisc.hpp"
@ -50,51 +54,66 @@
using namespace std;
using namespace kaz;
static const string KAZ_WEB_SITE = "https://kaz.bzh/";
static const string TMPL_DOWNLOAD = "{{DOWNLOAD}}";
static const string TMPL_FILENAME = "{{FILENAME}}";
static const string CID = "cid:";
static const string KAZ_WEB_SITE ("https://kaz.bzh/");
static const string TMPL_DOWNLOAD ("{{DOWNLOAD}}");
static const string TMPL_FILENAME ("{{FILENAME}}");
static const string CID ("cid:");
static const string KAZ_PLAIN_HR = "______________________________________________________________________________";
static const string KAZ_PLAIN_START = "~~ PJ-KAZ !"; // don't end whith space
static const string KAZ_PLAIN_STOP = KAZ_PLAIN_START+" ~~";
static const string KAZ_PLAIN_DONT_TOUCH = "(conservez cette partie intacte dans votre réponse si vous voulez transmettre les documents précédents)";
static const string KAZ_PLAIN_WARNING = "Attention : Kaz a dépollué ce message. Les pièces jointes ont été retirées et placées dans un dépôt provisoire. Elles seront automatiquement supprimées dans 1 mois. Si elles sont importantes et que vous souhaitez les conserver, vous devez utiliser les liens ci-dessous. Pour mieux comprendre la politique de nos services visitez kaz.bzh";
static const string KAZ_PLAIN_DOWLOAD_ONE = "Vos pièces jointes sont à télécharger individuellement ici :";
static const string KAZ_PLAIN_DOWLOAD_OTHER = "(Contenu dans des messages précédents)";
static const string KAZ_PLAIN_DOWLOAD_ALL = "Vous pouvez télécharger l'ensemble dans une archive là :";
// "l=/" => v1 compatibility
static const regex archiveURLSignature (".*(([&?]g=)|([&?]l=/)).*");
static const string HEAD = "<head>";
static const string HEAD_END = "</head>";
static const string KAZ_CSS_URL = "https://kaz.bzh/m/email.css";
static const string KAZ_CSS = "<link rel=\"stylesheet\" type=\"text/css\" charset=\"utf-8\" href=\""+KAZ_CSS_URL+"\"/>";
static const string A_END = "</a>";
static const string LI_BEGIN = "<li";
static const string CLASS_ONE = "class=\"one\"";
static const string LI_ONE = LI_BEGIN+" "+CLASS_ONE+">";
static const string LI_ALL = LI_BEGIN+" class=\"all\">";
static const string LI_END = "</li>";
static const string HREF_ONE = "href=\"";
static const string BODY_END = "</body>";
static const string HTML_END = "</html>";
static const string KAZ_HTML_TAG = "<!--KAZ"; // don't end whith space
static const string KAZ_HTML_START = KAZ_HTML_TAG+" START-->";
static const string KAZ_HTML_STOP = KAZ_HTML_TAG+" STOP-->";
static const string KAZ_PLAIN_HR ("______________________________________________________________________________");
static const string KAZ_PLAIN_START ("~~ PJ-KAZ !"); // don't end whith space
static const string KAZ_PLAIN_STOP (KAZ_PLAIN_START+" ~~");
static const string KAZ_PLAIN_DONT_TOUCH ("(conservez cette partie intacte dans votre réponse si vous voulez transmettre les documents précédents)");
static const string KAZ_PLAIN_WARNING ("Attention : Kaz a dépollué ce message. Les pièces jointes ont été retirées et placées dans un dépôt provisoire. "
"Elles seront automatiquement supprimées dans 1 mois. "
"Si elles sont importantes et que vous souhaitez les conserver, vous devez utiliser les liens ci-dessous. "
"Pour mieux comprendre la politique de nos services visitez kaz.bzh");
static const string KAZ_PLAIN_DOWLOAD_ONE ("Vos pièces jointes sont à télécharger individuellement ici :");
static const string KAZ_PLAIN_DOWLOAD_OTHER ("(Contenu dans des messages précédents)");
static const string KAZ_PLAIN_DOWLOAD_ALL ("Vous pouvez télécharger l'ensemble dans une archive là :");
static const string HEAD ("<head>");
static const string HEAD_END ("</head>");
static const string KAZ_CSS_URL ("https://kaz.bzh/m/email.css");
static const string KAZ_CSS ("<link rel=\"stylesheet\" type=\"text/css\" charset=\"utf-8\" href=\""+KAZ_CSS_URL+"\"/>");
static const string A_END ("</a>");
static const string LI_BEGIN ("<li");
static const string CLASS_ONE ("class=\"one\"");
static const string LI_ONE (LI_BEGIN+" "+CLASS_ONE+">");
static const string LI_ALL (LI_BEGIN+" class=\"all\">");
static const string LI_END ("</li>");
static const string HREF_ONE ("href=\"");
static const string KAZ_HTML_CONTENT ("<!DOCTYPE html><html lang=\"fr\"><head><meta charset=\"utf-8\"><title>KAZ</title>"+KAZ_CSS+"</head><body>");
static const string BODY_END ("</body>");
static const string HTML_END ("</html>");
static const string KAZ_HTML_TAG ("<!--KAZ"); // don't end whith space
static const string KAZ_HTML_START (KAZ_HTML_TAG+" START-->");
static const string KAZ_HTML_STOP (KAZ_HTML_TAG+" STOP-->");
// Textes précédents encodés en SGML
static const string KAZ_HTML_DONT_TOUCH = "(conservez cette partie intacte dans votre r&eacute;ponse si vous voulez transmettre les documents pr&eacute;c&eacute;dents)";
static const string KAZ_HTML_DOWLOAD_ONE = "Vos pi&egrave;ces jointes sont &agrave; t&eacute;l&eacute;charger individuellement ici :";
static const string KAZ_HTML_DOWLOAD_OTHER = "(Contenu dans des messages pr&eacute;c&eacute;dents)";
static const string KAZ_HTML_DOWLOAD_ALL = "Vous pouvez t&eacute;l&eacute;charger l'ensemble dans une archive l&agrave; :";
static const string KAZ_HTML_ARCHIVE = "archive";
static const string KAZ_HTML_DONT_TOUCH ("(conservez cette partie intacte dans votre r&eacute;ponse si vous voulez transmettre les documents pr&eacute;c&eacute;dents)");
static const string KAZ_HTML_DOWLOAD_ONE ("Vos pi&egrave;ces jointes sont &agrave; t&eacute;l&eacute;charger individuellement ici :");
static const string KAZ_HTML_DOWLOAD_OTHER ("(Contenu dans des messages pr&eacute;c&eacute;dents)");
static const string KAZ_HTML_DOWLOAD_ALL ("Vous pouvez t&eacute;l&eacute;charger l'ensemble dans une archive l&agrave; :");
static const string KAZ_HTML_ARCHIVE ("archive");
static const string KAZ_EMPTY_TEXT_PLAIN ("Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: base64\n");
static const string KAZ_ATTACHMENT_TEXT_HTML ("Content-Type: text/html; charset=utf-8\n"
"Content-Disposition: attachment; filename=\"" + Attachment::KAZ_ATTACH_NAME + "\"\n"
"Content-Transfer-Encoding: base64\n");
// ================================================================================
vector <string>
Attachment::stringsToUpdate ({KAZ_PLAIN_START, "\""+CID});
// ================================================================================
const string MainAttachment::templatePlainAddLink (" - "+TMPL_DOWNLOAD+" "+TMPL_FILENAME+"\r\n");
const string MainAttachment::templatePlainAllLink ("\r\n"+KAZ_PLAIN_DOWLOAD_ALL+"\r\n * "+TMPL_DOWNLOAD+"\r\n");
const string MainAttachment::templatePlainAddLink (" * "+TMPL_FILENAME+" <"+TMPL_DOWNLOAD+">\r\n");
const string MainAttachment::templatePlainAllLink ("\r\n * "+KAZ_PLAIN_DOWLOAD_ALL+" <"+TMPL_DOWNLOAD+">\r\n");
const string MainAttachment::templateHtmlHeader (KAZ_HTML_START+"<p style=\"clear: left; padding: 1pc 0 0 0; font-size:10px; color:#969696;\">"+KAZ_PLAIN_START+"</p><hr>\n"
"<div class=\"kaz\">"
@ -109,6 +128,35 @@ const string MainAttachment::templateHtmlFooter ("</ul></p>\n"
const regex MainAttachment::whiteSpaceRegEx ("\\s+");
// ================================================================================
const string
kaz::attachModeLabels[] = {
"None", "Footer", "Attachment", "Both"
};
const map<string, AttachMode>
kaz::attachModeMap = boost::assign::map_list_of
("none", NONE)
("footer", FOOTER)
("attachment", ATTACHMENT)
("both", BOTH)
;
ostream &
kaz::operator << (ostream &out, const AttachMode &attachMode) {
//BOOST_ASSERT (treeType >= MIN && treeType <= ALPHA);
return out << attachModeLabels [attachMode];
}
istream &
kaz::operator >> (istream &in, AttachMode &attachMode) {
string token;
in >> token;
auto pos = attachModeMap.find (boost::algorithm::to_lower_copy (token));
if (pos == attachModeMap.end ())
in.setstate (ios_base::failbit);
else
attachMode = pos->second;
return in;
}
// ================================================================================
void
MainAttachment::copy (ifstream &mbox, ofstream &outbox, const streamoff &begin, const streamoff &end) {
@ -163,11 +211,12 @@ void
MainAttachment::addLink (string &plain, string &html, const string &url, const string &name) const {
string plainNewOneLink (templatePlainAddLink);
replaceAll (plainNewOneLink, TMPL_DOWNLOAD, url);
replaceAll (plainNewOneLink, TMPL_FILENAME, name);
replaceAll (plainNewOneLink, TMPL_FILENAME, "\""+name+"\"");
plain += plainNewOneLink;
string htmlNewOneLink (templateHtmlAddLink);
string codedUrl (url);
replaceAll (codedUrl, "&", "&amp;");
// pb &amp;
// replaceAll (codedUrl, "&", "&amp;");
replaceAll (htmlNewOneLink, TMPL_DOWNLOAD, codedUrl);
replaceAll (htmlNewOneLink, TMPL_FILENAME, name);
html += htmlNewOneLink;
@ -208,22 +257,22 @@ MainAttachment::getDisclaim (string &plain, string &html) const {
return;
}
plain = "\r\n"+KAZ_PLAIN_START+"\r\n"+KAZ_PLAIN_HR+"\r\n"+KAZ_PLAIN_DONT_TOUCH+"\r\n\r\n"+KAZ_PLAIN_WARNING+"\r\n\r\n"+KAZ_PLAIN_DOWLOAD_ONE+"\r\n"+plainNewLinks;
plain = "\r\n"+KAZ_PLAIN_START+"\r\n"+KAZ_PLAIN_HR+"\r\n"+KAZ_PLAIN_DONT_TOUCH+"\r\n\r\n"+KAZ_PLAIN_DOWLOAD_ONE+"\r\n"+plainNewLinks;
html = templateHtmlHeader+htmlNewLinks;
if (previousLinks.size ()) {
plain += KAZ_PLAIN_DOWLOAD_OTHER+"\r\n"+plainOldLinks;
plain += "\r\n"+KAZ_PLAIN_DOWLOAD_OTHER+"\r\n"+plainOldLinks;
html += templateHtmlOtherLink+htmlOldLinks;
}
if (linkCount > 1 && archiveDownloadURL.length ()) {
string allPlainLinks (templatePlainAllLink);
replaceAll (allPlainLinks, TMPL_DOWNLOAD, archiveDownloadURL);
plain += allPlainLinks;
string allLinks (templateHtmlAllLink);
replaceAll (allLinks, TMPL_DOWNLOAD, archiveDownloadURL);
html += allLinks;
string allHtmlLinks (templateHtmlAllLink);
replaceAll (allHtmlLinks, TMPL_DOWNLOAD, archiveDownloadURL);
html += allHtmlLinks;
}
html += templateHtmlFooter;
plain += "\r\n\r\n"+KAZ_WEB_SITE+"\r\n"+KAZ_PLAIN_HR+"\r\n"+KAZ_PLAIN_STOP+"\r\n";
html += templateHtmlFooter+"\r\n";
plain += "\r\n\r\n"+KAZ_WEB_SITE+"\r\n\r\n"+KAZ_PLAIN_WARNING+"\r\n"+KAZ_PLAIN_HR+"\r\n"+KAZ_PLAIN_STOP+"\r\n";
// & => &amp; done
LOG ("plain: " << plain);
LOG ("html: " << html);
@ -239,12 +288,13 @@ MainAttachment::addPrevious (const string &href, const string &name, const bool
if (oldVal.length () && name.length () && !trust)
return;
previousLinks.erase (href);
previousLinks [href] = name;
previousLinks [href] = regex_replace (name, regex (R"([\t\r\n\"]+|(\\\")|(>\s*))"), "");
LOG ("inserted: " << href << ": " << previousLinks[href]);
}
void
MainAttachment::extractLinks (const string &extractedPlainKAZ) {
// plain text => "* name <url>"
DEF_LOG ("Attachment::extractedPlainKAZ", "extractedPlainKAZ: " << extractedPlainKAZ);
for (string::size_type startPos (0);
(startPos = extractedPlainKAZ.find ("http", startPos)) != string::npos;
@ -255,24 +305,32 @@ MainAttachment::extractLinks (const string &extractedPlainKAZ) {
const string href (extractedPlainKAZ.substr (startPos, stopPos-startPos));
LOG ("plain href: " << href);
if (extractedPlainKAZ [stopPos] && extractedPlainKAZ [stopPos] != '\n')
if (extractedPlainKAZ [stopPos])
++stopPos;
streamoff stopName = startPos;
startPos = stopPos;
// get all href but KAZ_WEB_SITE
// the archive link will be skip by filter.sh
if (href == KAZ_WEB_SITE)
continue;
string::size_type nextPos = extractedPlainKAZ.find ("http", startPos);
string name (extractedPlainKAZ, startPos, (nextPos == string::npos ? extractedPlainKAZ.length () : nextPos) - startPos);
// backward find name
string::size_type startName = extractedPlainKAZ.rfind ("* ", stopName);
string name;
if (startName != string::npos) {
name = string (extractedPlainKAZ, startName+3, stopName - startName - 3);
// skip [> \r\n\t]
nextPos = name.find_first_not_of ("[> \t\r\n]");
string::size_type nextPos = name.find_first_not_of ("[>< \t\r\n\"]");
if (nextPos != string::npos)
name.erase (0, nextPos);
// stop before [>\r\n\t]
nextPos = name.find_first_of ("[>\t\r\n]");
nextPos = name.find_first_of ("[\"<]");
if (nextPos != string::npos)
name.erase (nextPos);
}
LOG ("plain name: " << name);
addPrevious (href, name);
}
@ -281,6 +339,7 @@ MainAttachment::extractLinks (const string &extractedPlainKAZ) {
// ================================================================================
void
MainAttachment::extractLinks (const vector<string> &liOne) {
// html text => "<li ...><a href="url">name</a>"
DEF_LOG ("Attachment::extractedPlainKAZ", "liOne.size: " << liOne.size ());
for (const string &one : liOne) {
if (caseInsensitiveFind (one, CLASS_ONE) == string::npos)
@ -317,7 +376,7 @@ MainAttachment::extractPreviousKAZ (ifstream &mbox) {
DEF_LOG ("MainAttachment::extractPreviousKAZ", "");
string extractedPlainKAZ, extractedHtmlKAZ;
for (const Attachment *attachP : allMarkedPtrs) {
if (!attachP->toUpdate || isBase64Encoding ())
if (!(attachP->toUpdate || attachP->isKazAttachment)) // isKazAttachment => toUpdate
continue;
string textProp = attachP->getProp (contentTypeToken, textRegEx);
if (textProp.empty ())
@ -353,16 +412,20 @@ MainAttachment::extractPreviousKAZ (ifstream &mbox) {
void
MainAttachment::removePreviousArchive () {
vector<string> toRemove;
for (map <string, string>::const_iterator it = previousLinks.begin (); it != previousLinks.end (); ++it)
if (it->first.find ("&l=/") != string::npos)
toRemove.push_back (it->first);
for (map <string, string>::const_iterator it = previousLinks.begin (); it != previousLinks.end (); ++it) {
const string key (it->first);
if (regex_match (key, archiveURLSignature))
toRemove.push_back (key);
}
for (string old : toRemove)
previousLinks.erase (old);
}
// ================================================================================
MainAttachment::MainAttachment (ifstream &mbox)
: Attachment (mbox, initTmpLevel (), 0, initTmpPos ()) {
: Attachment (mbox, initTmpLevel (), 0, initTmpPos ()),
emptyEMail (false),
previousKazAttachment (false) {
DEF_LOG ("MainAttachment::MainAttachment", "");
string line;
for (; getline (mbox, line); )
@ -376,6 +439,7 @@ MainAttachment::markSignificant (const streamoff &minAttachSize, ifstream &mbox)
DEF_LOG ("MainAttachment::markSignificant", "minAttachSize: " << minAttachSize);
bool plainMarked (false), htmlMarked (false);
markDisclaim (plainMarked, htmlMarked);
emptyEMail = ! (plainMarked || htmlMarked);
Attachment::markSignificant ("", minAttachSize, mbox, allMarkedPtrs);
}
@ -419,7 +483,7 @@ MainAttachment::extract (ifstream &mbox, const SizeArg &minSize) const {
int attachCount (0);
string dirName, mediaName;
for (Attachment *attachP : allMarkedPtrs) {
if (!attachP->toExtract)
if (attachP->isKazAttachment || !attachP->toExtract)
continue;
newPjEntry (attachCount, attachP->getContentType (), attachP->getAttachName (), dirName, mediaName);
++attachCount;
@ -494,15 +558,15 @@ MainAttachment::extract (ifstream &mbox, const SizeArg &minSize) const {
// ================================================================================
void
MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize) {
DEF_LOG ("MainAttachment::substitute", "minSize: " << minSize);
MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize, const AttachMode &attachMode) {
DEF_LOG ("MainAttachment::substitute", "minSize: " << minSize << " AttachMode: " << attachMode);
// preparation
extractPreviousKAZ (mbox);
removePreviousArchive ();
map<const string, const string> translateHtml;
for (Attachment *attachP : allMarkedPtrs)
if (attachP->toExtract) {
if (attachP->toExtract && !attachP->isKazAttachment) {
readDownloadUrl (attachP->downloadUrl);
if (attachP->downloadUrl.empty ()) {
LOG ("no change");
@ -511,7 +575,7 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
}
if (attachP->cid.length ()) {
string tmp (attachP->downloadUrl);
replaceAll (tmp, "&", "&amp;");
//replaceAll (tmp, "&", "&amp;");
translateHtml.insert (pair<const string, const string> (CID+attachP->cid, tmp));
}
}
@ -520,19 +584,36 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
continue;
for (EmbeddedData &embedded : attachP->embeddedData)
readDownloadUrl (embedded.downloadUrl);
// XXX test empty ?
}
readArchiveUrl ();
removePreviousArchive ();
string plainDisclaim, htmlDisclaim;
getDisclaim (plainDisclaim, htmlDisclaim);
// copy email
streamoff curPos = 0;
copy (mbox, outbox, curPos, contentPos);
curPos = contentPos;
if (plainDisclaim.size ()) {
if (emptyEMail && (attachMode & FOOTER)) {
// check no main text
LOG ("Force main text");
LOG_BUG (boundary.empty () || ! subAttachements.size (), /**/, "eMailShrinker: can't force add footer M9: : " << *this);
string content (plainDisclaim);
base64Encode (content);
outbox << boundary.substr (0, boundary.length () -2) << endl
<< KAZ_EMPTY_TEXT_PLAIN << endl
<< content << endl;
outbox.flush ();
}
}
for (Attachment *attachP : allMarkedPtrs) {
copy (mbox, outbox, curPos, attachP->beginInParent);
LOG_BUG (attachP->toUpdate && attachP->toExtract, /**/, "eMailShrinker: bug M5: update and extract. pos: " << attachP->beginPos);
if (attachP->toExtract) {
LOG ("skip Extracted");
if (attachP->toExtract || attachP->isKazAttachment) {
LOG ("skip Extracted or previous attachments");
} else if (attachP->toUpdate) {
string textProp = attachP->getProp (contentTypeToken, textRegEx);
@ -580,7 +661,7 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
}
if (isPlain)
removeSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
if (isDisclaimer) {
if (isDisclaimer && (attachMode & FOOTER)) {
if (isHtml) {
for (string endTag : {BODY_END, HTML_END}) {
LOG ("try tag: " << endTag);
@ -603,6 +684,20 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
outbox.flush ();
curPos = attachP->endPos;
}
if (plainDisclaim.size () && (attachMode & ATTACHMENT)) {
// XXX si pas de multipart
LOG ("Add kaz attachment");
LOG_BUG (boundary.empty () || ! subAttachements.size (), /**/, "eMailShrinker: can't add Kaz attachment M10: : " << *this);
streamoff lastPos = subAttachements.back ().endPos;
copy (mbox, outbox, curPos, lastPos);
curPos = lastPos;
string content (KAZ_HTML_CONTENT+htmlDisclaim+BODY_END+HTML_END);
base64Encode (content);
outbox << boundary.substr (0, boundary.length () -2) << endl
<< KAZ_ATTACHMENT_TEXT_HTML << endl
<< content << endl;
outbox.flush ();
}
copy (mbox, outbox, curPos, endPos);
outbox.close ();
}

View File

@ -32,7 +32,7 @@
// knowledge of the CeCILL-B license and that you accept its terms. //
////////////////////////////////////////////////////////////////////////////
#define LAST_VERSION "2.0 2022-02-08 eMailShrinker"
#define LAST_VERSION "2.3 2022-11-25 eMailShrinker"
#include <iostream>
#include <fstream>
@ -66,8 +66,8 @@ usage (const string &msg = "", const bool &hidden = false) {
cout << endl
<< "Usage: " << endl
<< " A) " << prog << " -u mbox > url-list" << endl
<< " B) " << prog << " [-s size] [-d dirName}] mbox > file-list" << endl
<< " C) " << prog << " [-s size] mbox altered-mbox < url-list" << endl
<< " B) " << prog << " [-s size] [-d dirName] mbox > file-list" << endl
<< " C) " << prog << " [-s size] [-m {Footer|Attachment|Both}] mbox altered-mbox < url-list" << endl
<< endl << " filter attachments" << endl << endl
<< " A: list previous embded url need to be refresh (no added option)" << endl
<< " => downloadURL list" << endl
@ -108,15 +108,16 @@ main (int argc, char** argv) {
DEF_LOG ("main:", "");
prog = argv [0];
bool
debugFlag (false),
helpFlag (false),
versionFlag (false),
updateListFlag (false),
useTheForceLuke (false),
listFlag (false);
listFlag (false),
debugFlag (false);
string inputName, outputName;
bfs::path extractDir (bfs::temp_directory_path ());
SizeArg minAttachSize ("48 Ki");
AttachMode attachMode (FOOTER);
try {
mainDescription.add_options ()
@ -125,6 +126,7 @@ main (int argc, char** argv) {
("size,s", value<SizeArg> (&minAttachSize)->default_value (minAttachSize), "minimum size for extration")
("updateList,u", bool_switch (&updateListFlag), "list URL need refresh")
("extractDir,d", value<bfs::path> (&extractDir)->default_value (extractDir), "set tmp directory name for extraction")
("mode,m", boost::program_options::value<AttachMode> (&attachMode)->default_value (attachMode), "set attachment mode")
;
hide.add_options ()
@ -188,10 +190,10 @@ main (int argc, char** argv) {
MainAttachment attachment (mbox);
mbox.close ();
if (attachment.getBoundary ().empty ()) {
cerr << "no attachment" << endl;
return 1;
}
// if (attachment.getBoundary ().empty ()) {
// cerr << "no attachment" << endl;
// return 1;
// }
// parse structure
mbox.open (inputName);
attachment.markSignificant (minAttachSize, mbox);
@ -219,9 +221,13 @@ main (int argc, char** argv) {
}
// case substitute
if (attachMode == NONE) {
cerr << endl << prog << ": attachMode can't be NONE (forced FOOTER mode)" << endl;
attachMode = FOOTER;
}
mbox.open (inputName);
ofstream outbox (outputName);
attachment.substitute (mbox, outbox, minAttachSize);
attachment.substitute (mbox, outbox, minAttachSize, attachMode);
showTime ("Substitution");
return 0;
}

View File

@ -32,7 +32,7 @@
// knowledge of the CeCILL-B license and that you accept its terms. //
////////////////////////////////////////////////////////////////////////////
#define LAST_VERSION "1.0 2021-02-21 jirafeauAPI"
#define LAST_VERSION "1.1 2022-10-30 jirafeauAPI"
#include <iostream>
#include <string>
@ -122,8 +122,8 @@ main (int argc, char** argv) {
contentType,
attachName,
urlBase ("http://file.kaz.bzh"),
apiPage ("/script.php"),
downloadPage ("/f.php"),
uploadPage ("/a.php"),
updatePage ("/a.php"),
minimumAvailability ("month"),
proxy;
@ -144,8 +144,8 @@ main (int argc, char** argv) {
("useTheForceLuke", bool_switch (&useTheForceLuke), "display hidded options")
("debug,g", bool_switch (&debugFlag), "debug mode")
("proxy,p", value<string> (&proxy)->default_value (proxy), "set proxy (proxy-host.org:8080)")
("uploadPage,u", value<string> (&apiPage)->default_value (apiPage), "upload page")
("downloadPage,d", value<string> (&downloadPage)->default_value (downloadPage), "download page")
("uploadPage,u", value<string> (&uploadPage)->default_value (uploadPage), "upload page")
("updatePage,v", value<string> (&updatePage)->default_value (updatePage), "update page")
;
options_description cmd ("All options");
@ -220,8 +220,8 @@ main (int argc, char** argv) {
switch (jirCmd) {
case SEND: {
LOG ("SEND: " << (urlBase+apiPage));
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+apiPage).c_str ());
LOG ("SEND: " << (urlBase+uploadPage));
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+uploadPage).c_str ());
LOG ("maxUploadSize: " << maxUploadSize);
long uploadsize = (size_t) maxUploadSize;
@ -264,8 +264,8 @@ main (int argc, char** argv) {
break;
case UPDATE: {
LOG ("UPDATE: " << (urlBase+downloadPage));
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+downloadPage).c_str ());
LOG ("UPDATE: " << (urlBase+updatePage));
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+updatePage).c_str ());
LOG ("h: " << inputFileName);
part = curl_mime_addpart (multipart);
@ -281,12 +281,13 @@ main (int argc, char** argv) {
}
curl_easy_setopt (easyhandle, CURLOPT_MIMEPOST, multipart);
curl_easy_perform (easyhandle);
CURLcode res (curl_easy_perform (easyhandle));
curl_easy_cleanup (easyhandle);
cout << readBuffer << endl;
showTime ("Upload");
if (res != CURLE_OK)
cerr << prog << " failed: " << curl_easy_strerror (res) << endl;
return 0;
}

View File

@ -35,9 +35,9 @@
#ifndef _kaz_Attachment_hpp
#define _kaz_Attachment_hpp
#include <string>
#include <regex>
#include <map>
#include <regex>
#include <string>
#include <utility>
#include "EmbeddedData.hpp"
@ -54,7 +54,7 @@ namespace kaz {
//static const vector<const string> stringsToUpdate;
static vector<string> stringsToUpdate;
/*! mime tokens */
static const string contentTypeToken, contentDispositionToken, contentTransferEncodingToken, base64Token, quotedPrintableToken, contentIDToken, PLAIN, HTML, RELATED, ALTERNATIVE;
static const string contentTypeToken, contentDispositionToken, contentTransferEncodingToken, base64Token, quotedPrintableToken, contentIDToken, PLAIN, HTML, RELATED, ALTERNATIVE, KAZ_ATTACH_NAME;
/*! pattern to extract mime values */
static const regex nameRegEx, nameCharsetRegEx, boundaryRegEx, cidDefRegEx, textRegEx, multiRegEx;
@ -100,7 +100,7 @@ namespace kaz {
/*! char position of attachment content */
streamoff contentPos, endPos;
/*! properties of the attachment */
bool toExtract, toUpdate, toDisclaim;
bool toExtract, toUpdate, toDisclaim, isKazAttachment;
/*! id of an image embedded in mbox */
string cid;
/*! url to replace the attachment */

View File

@ -44,6 +44,13 @@ namespace kaz {
namespace bfs = boost::filesystem;
// ================================================================================
/*! place to add download link (footer, attachment or both) */
enum AttachMode { NONE = 0, FOOTER = 1, ATTACHMENT = 2, BOTH = (FOOTER|ATTACHMENT) };
extern const string attachModeLabels[];
extern const map<string, AttachMode> attachModeMap;
ostream &operator << (ostream &out, const AttachMode &attachMode);
istream &operator >> (istream &in, AttachMode &attachMode);
/*! root level of e-mail structure */
class MainAttachment : public Attachment {
public:
@ -83,6 +90,10 @@ namespace kaz {
bfs::path extractDir;
/*! URL for download archives */
string archiveDownloadURL;
/*! if no main text in email can be used to add disclaim */
bool emptyEMail;
/*! if contain previous kaz attachment */
bool previousKazAttachment;
/*! subset in the tree of all attachments to be consider for extraction or modification */
vector<Attachment *> allMarkedPtrs;
@ -113,7 +124,7 @@ namespace kaz {
/*! extract big attachments in mbox to extractDir and write to stdout le dirname of each extraction */
void extract (ifstream &mbox, const SizeArg &minSize) const;
/*! substitute big attachments by the url give in stdin */
void substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize);
void substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize, const AttachMode &attachMode);
};
// ================================================================================

10
src/mainpage.md Normal file
View File

@ -0,0 +1,10 @@
**Dépollueur**
Main Programmes:
* [eMailShrinker](eMailShrinker_8cpp.html)
* [jirafeauAPI](jirafeauAPI_8cpp.html)
Main classes:
* [MainAttachment](classkaz_1_1MainAttachment.html)
* [Attachment](classkaz_1_1Attachment.html)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
#/bin/bash
# GME
# Ici on défini une liste de tests à effectuer sur les mails reçus (et donc dépollués !).
# Touts les mails sont concatennés avant vérification (egrep) des regexp donc on veillera,
# donc nommer différement les pièces sur les mails de tests si on a besoin de retrouver quel est le mail qui plante
# pour chaque test
TESTS_DESCRIPTION=(); # Une description pour l'affichage du résultat
TESTS_REGEXP=(); # Quoi qu'on doit trouver ?
TESTS_MATCHING_LINES=(); # Combien d'occurences de ça dans l'ensemble des messages ?
TESTS_DESCRIPTION+=("Le nombre de mails correctement dépollués");
TESTS_REGEXP+=(".*Attention : Kaz a \S+ ce message.*");
TESTS_MATCHING_LINES+=(1);
TESTS_DESCRIPTION+=("La piece est correctement nommée pour un mail normal");
TESTS_REGEXP+=("\\* \"pdftest.pdf\" <https://depot.[^/]*/");
TESTS_MATCHING_LINES+=(1);
TESTS_DESCRIPTION+=("La piece est correctement nommée pour un mail sans texte");
TESTS_REGEXP+=("\\* \"pdftestmailsanstexte.pdf\" <https://depot.[^/]*/");
TESTS_MATCHING_LINES+=(1);
TESTS_DESCRIPTION+=("La piece est correctement nommée pour une piece sans guillemets");
TESTS_REGEXP+=("\\* \"pdftestSansGuillemets.pdf\" <https://depot.[^/]*/");
TESTS_MATCHING_LINES+=(1);
TESTS_DESCRIPTION+=("L'encodage du mail est correct");
TESTS_REGEXP+=(".*é.*");
TESTS_MATCHING_LINES+=(0);

15660
test/mails/mail-sans-texte.eml Normal file

File diff suppressed because it is too large Load Diff

15667
test/mails/normal.eml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

456
test/runTests.sh Normal file
View File

@ -0,0 +1,456 @@
#/bin/bash
# --- GME ---
# Envois full automatisés de mails dits bizarres vers un serveur kaz,
# dans le but de tester bon fonctionnement du dépollueur
#
# On enregistre en .eml dans le dossier mails, des messages "mal construits" pouvant causer pb au dépollueur.
# Les mails ont les champs suivants à l'interieur: %DATE% %FROM_ADDRESS% %TO_ADDRESS%
# Le fichier expectedResults permet de définir des regexp qu'on doit vérifier sur le mail reçu.
#
# Le script les envoie un par un via l'utilitaire swaks
# - interne -> interne
# - interne -> externe
# - externe -> interne
#
# Un petit warning, ce script fait du mailing moche (on balance un paquet de mails volontairement mal construits).
# Vous savez ce que vous faites ! Et si vous ne savez pas, ne le faites pas.
# En particulier si on utilise des mails qui sortent et entrent ... (blacklistings / etc ...)
# On préfèrera faire les tests sur un environnement de dev bien sûr !
TEST_DIR=$(cd "$(dirname $0)"; pwd)
. $TEST_DIR/mails/expectedResults.sh
NBMAILS=$(ls $TEST_DIR/mails/*.eml | wc -l)
# random key
KEY="TESTDEP-$(echo $RANDOM | md5sum | head -c 20;)"
# ou qu'il est le depollueur ?
SERVEUR_TO_TEST=
SERVEUR_IS_LOCALHOST=0
# s'il est pas en local, il faut bien pouvoir s'identifier
USERFROM=
USERTO=
PASSWORD=
# un mail externe pour tester entrant / sortant
EXTERNAL_EMAIL=
EXTERNAL_SMTP=
EXTERNAL_USER=
EXTERNAL_PASSWORD=
EXTERNAL_SMTP_AUTH=1
EXTERNAL_TESTS_ENABLED=1
EXTERNAL_SMTP_ENABLED=1
EXTERNAL_ONLY=0
#un peu de debug
VERBOSE=0
#ou si on préfère ne rien savoir
QUIET=0
#swaks est installé ?
SWAKS_OK=$(dpkg-query -W --showformat='${Status}\n' swaks 2>/dev/null | grep "install ok installed")
# les résultats
SKIP_RESULTS=0
KEEP_MAILS_ON_SERVEURS=0
#mutt est installé ?
MUTT_OK=$(dpkg-query -W --showformat='${Status}\n' mutt 2>/dev/null | grep "install ok installed")
usage () {
echo "${PRG} [-h] -s <smtp_a_tester> -a <user> [-l] [-p <password>] [-v|-q] [-eq] [-ea] [-em <mail-ext>] [-es <smtp-ext>] [-eu <user-ext>] [-ep <password-ext>]"
echo " Tests full-automatisés du dépollueur."
echo " On envoie une série de mails et on vérifie que le lien généré est bon."
echo " -h | --help : Display this help."
echo " -s | --server : Quel serveur je teste ? (fqnd)"
echo " -l | --localhost : si le script est execute depuis le serveur test"
echo " -f | --from : Un compte à utiliser sur ce serveur en tant qu'expediteur"
echo " -t | --to : Un compte à utiliser sur ce serveur en tant que destinataire (optionnel, l expediteur est utilise sinon)"
echo " -p | --password : Le mot de passe de l'expéditeur si le script est executé à distance"
echo " -ed | --ext-disabled : Ne pas faire de tests externes"
echo " -eo | --ext-only : Ne faire que les tests externes"
echo " -em | --ext-mail : Un mail externe pour des tests vers / depuis l'exterieur"
echo " -es | --ext-server : Quel serveur je teste ?"
echo " -eu | --ext-user : Un identifiant pour smtp ext si différents de mail"
echo " -ep | --ext-password : Le mot de passe associé pour le ext-user ou mail"
echo " -ena | --ext-no-auth : Le smtp externe n'a pas besoin d'authentifications (FAI par exemple)"
echo " -rd | --results-disabled : Ne pas tenter d'aller chercher les résultats"
echo " -ksm | --keep-sended-mails : Laisser les messages envoyés sur les serveurs de destination"
echo " -v or -V display more informations"
echo " -q or -Q Quiet mode"
echo "Un petit warning, ce script fait du mailing moche (on balance un paquet de mails volontairement mal construits). "
echo "Vous savez ce que vous faites ! Et si vous ne savez pas, ne le faites pas."
}
cleanupPackage () {
# on vire swaks si on l'a installé
# eventuellement on le fait même silently
package=$1;
quietMode=$2;
[ -z $quietMode ] && quietMode=0;
[ $quietMode -eq 0 ] && echo "$package a été installé, vous permettez que je désinstalle .. !";
if [ $quietMode -eq 0 ]
then
apt-get -y remove $package;
apt-get -y purge $package;
else
apt-get -yq remove $package;
apt-get -yq purge $package;
fi;
}
# récupération des arguments
[ -z "$1" ] && { usage;exit; }
for arg in $*
do
case "$arg" in
'-h' | '--help' )
usage
shift
exit;;
'-s' | '--server')
shift;
SERVEUR_TO_TEST=$1
shift;;
'-l' | '--localhost')
SERVEUR_IS_LOCALHOST=1
shift;;
'-f' | '--from')
shift;
USERFROM=$1
shift;;
'-p' | '--password')
shift;
PASSWORD=$1
shift;;
'-t' | '--to')
shift;
USERTO=$1
shift;;
'-ed' | '--ext-disabled')
EXTERNAL_TESTS_ENABLED=0;
EXTERNAL_SMTP_ENABLED=0;
shift;;
'-em' | '--ext-mail')
shift;
EXTERNAL_EMAIL=$1
shift;;
'-es' | '--ext-server')
shift;
EXTERNAL_SMTP=$1
shift;;
'-eu' | '--ext-user')
shift;
EXTERNAL_USER=$1
shift;;
'-ep' | '--ext-password')
shift;
EXTERNAL_PASSWORD=$1
shift;;
'-ena' | '--ext-no-auth')
EXTERNAL_SMTP_AUTH=0
shift;;
'-eo' | '--ext-only')
EXTERNAL_ONLY=1
shift;;
'-v' | '-V' )
VERBOSE=1
shift;;
'-q' | '-Q' )
QUIET=1
shift;;
'-rd' | '--results-disabled')
SKIP_RESULTS=1
shift;;
'-ksm' | '--keep-sended-mails')
KEEP_MAILS_ON_SERVEURS=1
shift;;
*)
esac
done;
[ $VERBOSE -eq 1 -a $QUIET -eq 1 ] && echo 'Les options -q et -v ne sont pas compatibles.' && usage;
[ $VERBOSE -eq 1 ] && echo "Checking for swaks : $SWAKS_OK";
if [ -z "$SWAKS_OK" ];
then
if [ $QUIET -eq 0 ]
then
echo "Swaks doit être installé, je le fait pour vous si j'ai les droits !";
while true; do
read -p "On y va ? [Yn] :" yn
case $yn in
[YyoO]* ) break;;
[Nn]* ) echo "Swaks doit être installé, les tests en dépendent"; exit;;
* ) break;;
esac
done;
apt-get update;
apt-get -y install swaks;
else
apt-get -q update;
apt-get -qy install swaks;
fi;
SWAKS_INSTALLED=$(dpkg-query -W --showformat='${Status}\n' swaks 2>/dev/null | grep "install ok installed")
if [ -z "$SWAKS_INSTALLED" ]
then
echo "Swaks doit être installé, et je ne suis pas root visiblement.";
echo "Soit le faire à la main, soit je m'en charge (apt install et remove à la fin), mais il me faut les droits root !";
exit;
fi;
trap 'cleanupPackage swaks $QUIET' EXIT;
fi
if [ $SKIP_RESULTS -eq 0 -a -z "$MUTT_OK" ];
then
[ $VERBOSE -eq 1 ] && echo "Checking for mutt : $MUTT_OK";
if [ $QUIET -eq 0 ]
then
echo "Mutt doit être installé, je le fait pour vous si j'ai les droits !";
while true; do
read -p "On y va ? [Yn] :" yn
case $yn in
[YyoO]* ) break;;
[Nn]* ) echo "Mutt doit être installé, les tests en dépendent"; exit;;
* ) break;;
esac
done;
apt-get update;
apt-get -y install mutt;
else
apt-get -q update;
apt-get -qy install mutt;
fi;
MUTT_INSTALLED=$(dpkg-query -W --showformat='${Status}\n' swaks 2>/dev/null | grep "install ok installed")
if [ -z "$MUTT_INSTALLED" ]
then
echo "Mutt doit être installé, et je ne suis pas root visiblement.";
echo "Soit le faire à la main, soit je m'en charge (apt install et remove à la fin), mais il me faut les droits root !";
exit;
fi;
trap 'cleanupPackage mutt $QUIET' EXIT;
fi
# si les paramètres n'ont pas été renseignés via les arguments du script,
# on prompt ceux qui sont necessaires
[ $QUIET -eq 1 -a -z "$SERVEUR_TO_TEST" ] && SERVEUR_TO_TEST="mail.kaz.local"; #en mode quiet, on prend les options par défaut
if [ -z "$SERVEUR_TO_TEST" ]
then
[ $VERBOSE -eq 1 ] && echo "-- Le serveur n'a pas été renseigné (il faut un fqdn):";
read -p "Le serveur à tester ? [mail.kaz.local] :" SERVEUR_TO_TEST;
[ -z "$SERVEUR_TO_TEST" ] && SERVEUR_TO_TEST="mail.kaz.local";
fi;
[ $QUIET -eq 1 -a -z "$USERFROM" ] && SERVEUR_TO_TEST="contact1@kaz.local"; #en mode quiet, on prend les options par défaut
if [ -z "$USERFROM" ]
then
[ $VERBOSE -eq 1 ] && echo "-- Il me faut également un compte mail qui envoie :";
read -p "Email Expediteur ? [contact1@kaz.local]" USERFROM;
[ -z "$USERFROM" ] && USERFROM="contact1@kaz.local";
fi;
[ -z "$USERTO" ] && USERTO="$USERFROM"; #sauf si précisé en option
# si on est en local, normalement les mails partent sans besoin de renseigner l'authentification
# sinon il faut un mot de passe pour le smtp
if { [ $SKIP_RESULTS -eq 0 ] || [ $SERVEUR_IS_LOCALHOST -eq 0 ]; } && [ -z "$PASSWORD" ];
then
[ $VERBOSE -eq 1 ] && echo "-- Le password à utiliser n'a pas été renseigné :";
read -s -p "Le password ? [toto]" PASSWORD;
[ -z "$PASSWORD" ] && PASSWORD="toto";
fi;
# utilisation d'un mail exterieur et eventuellement un smtp exterieur
if [ -z "$EXTERNAL_EMAIL" -a $EXTERNAL_TESTS_ENABLED -eq 1 -a $QUIET -eq 0 ]
then
[ $VERBOSE -eq 1 ] && echo "-- Les tests vers/depuis l'exterieur n'ont pas été desactivé via l'option -ed.";
while true; do
read -p "On fait des tests depuis / vers l'exterieur aussi ? [Yn] :" yn
case $yn in
[YyoO]* ) break;;
[Nn]* ) EXTERNAL_TESTS_ENABLED=0; EXTERNAL_SMTP_ENABLED=0; break;;
* ) break;;
esac
done;
if [ $EXTERNAL_TESTS_ENABLED -eq 0 ]
then
[ $VERBOSE -eq 1 ] && echo "-- Les tests vers/depuis l'exterieur annulés";
else
[ $VERBOSE -eq 1 ] && echo "-- Ok mais je n'ai toujours pas l'adresse exterieure à utiliser.";
read -p "Mail externe ? :" EXTERNAL_EMAIL;
fi
fi
if [ -z "$EXTERNAL_SMTP" -a $EXTERNAL_TESTS_ENABLED -eq 1 -a $QUIET -eq 0 ]
then
[ $VERBOSE -eq 1 ] && echo "-- smtp, je pourrais le deviner à partir du mail mais ... j'ai la flemme là.";
echo "Pour les tests Depuis l'exterieur, il me faut aussi un smtp.Laisser vide si pas de tests depuis l'exterieur."
read -p "smtp externe ? :" EXTERNAL_SMTP;
[ -z $EXTERNAL_SMTP ] && EXTERNAL_SMTP_ENABLED=0;
fi
# authent pour le smtp ext
if [ -z "$EXTERNAL_USER" -a $EXTERNAL_SMTP_AUTH -eq 1 -a $EXTERNAL_SMTP_ENABLED -eq 1 -a $QUIET -eq 0 ]
then
[ $VERBOSE -eq 1 ] && echo "L'authentification au smtp externe n'a pas été désactivée avec l'option -ea :";
[ $VERBOSE -eq 1 ] && echo "Le user à utiliser pour ce smtp externe n'a pas été renseigné :";
read -p "Le user du smtp ? " EXTERNAL_USER;
fi
if [ -z "$EXTERNAL_PASSWORD" -a $EXTERNAL_SMTP_AUTH -eq 1 -a $EXTERNAL_SMTP_ENABLED -eq 1 -a $QUIET -eq 0 ]
then
[ $VERBOSE -eq 1 ] && echo "L'authentification au smtp externe n'a pas été désactivée avec l'option -ea :";
[ $VERBOSE -eq 1 ] && echo "Le password à utiliser pour ce smtp externe n'a pas été renseigné :";
read -s -p "Le password pour le smtp ? " EXTERNAL_PASSWORD;
fi
####
#### Fin de la récupération des paramètres du script. On balance les mails !
####
if [ $VERBOSE -eq 1 ]
then
echo 'Paramètres : '
echo '------------'
echo " Serveur : $SERVEUR_TO_TEST"
echo " Expéditeur interne : $USERFROM"
echo " Destinataire interne : $USERTO"
echo ' Password : ***'
echo " Tests vers externes : $EXTERNAL_TESTS_ENABLED"
echo " Tests depuis externe : $EXTERNAL_SMTP_ENABLED"
echo " Mail externe : $EXTERNAL_EMAIL"
echo " Auth externe : $EXTERNAL_USER"
echo ''
echo ''
fi
if [ $QUIET -eq 0 ]
then
sleep 2;
echo "OK on va y aller ... mais j'attend encore 3 secondes pour donner le temps pour un Ctrl C"
sleep 3;
fi
if [ $VERBOSE -eq 1 ]
then
echo "C'est parti !";
# vous êtes sûr ? bon d'accord c'est chiant,
# mais si on a cree des mails vraiment veroles, et qu'on est en train de les balancer sur la en prod, on peut avoir un doute ...
fi
sleep 2;
if [ $EXTERNAL_ONLY -eq 0 ]
then
echo "1 ----- $NBMAILS Mails envoyés depuis $USERFROM vers $USERTO ----";
for MAIL in "$TEST_DIR/mails/"*.eml
do
echo "$MAIL";
options=(-f $USERFROM -t $USERTO -d $MAIL --h-From: "\"$KEY\" <$USERFROM>");
[ $SERVEUR_IS_LOCALHOST -eq 0 ] && options+=(-s $SERVEUR_TO_TEST -p 587 --tlso -au $USERFROM -ap $PASSWORD);
[ $QUIET -eq 1 ] && options+=(--silent);
[ $VERBOSE -eq 0 ] && options+=(-n);
swaks "${options[@]}";
done
fi
if [ $EXTERNAL_TESTS_ENABLED -eq 1 ]
then
echo "2 ----- $NBMAILS Mails envoyés depuis $USERFROM vers $EXTERNAL_USER ----";
for MAIL in "$TEST_DIR/mails/"*.eml
do
options=(-f $USERFROM -t $EXTERNAL_EMAIL -d $MAIL -s $SERVEUR_TO_TEST --tlso --h-From: "\"$KEY\" <$USERFROM>");
[ $SERVEUR_IS_LOCALHOST -eq 0 ] && options+=(-p 587 -au $USERFROM -ap $PASSWORD); # on rajoute l'authetification
[ $QUIET -eq 1 ] && options+=(--silent);
[ $VERBOSE -eq 0 ] && options+=(-n);
swaks "${options[@]}";
done
fi
if [ $EXTERNAL_SMTP_ENABLED -eq 1 ]
then
if [ $SERVEUR_IS_LOCALHOST -eq 1 ]
then
[ $QUIET -eq 0 ] && echo "3 ----- Mails envoyés depuis l'extérieur vers localhost ... heu une autre fois en fait ... ";
[ $VERBOSE -eq 1 ] && echo "-- Mais si vous renseignez un fqdn pour le serveur je pourrais essayer ...";
else
echo "3 ----- $NBMAILS Mails envoyés depuis $EXTERNAL_EMAIL vers $USERTO ----";
for MAIL in "$TEST_DIR/mails/"*.eml
do
options=(-f $EXTERNAL_EMAIL -t $USERTO -d $MAIL -s $EXTERNAL_SMTP -p 587 --tlso --h-From: "\"$KEY\" <$USERFROM>");
[ $EXTERNAL_SMTP_AUTH -eq 1 ] && options+=(-au $EXTERNAL_USER -ap $EXTERNAL_PASSWORD);
[ $QUIET -eq 1 ] && options+=(--silent);
[ $VERBOSE -eq 0 ] && options+=(-n);
swaks "${options[@]}";
done
fi
fi
####
#### Et bien maintenant on va voir les résultats !
####
if [ $SKIP_RESULTS -eq 0 ]
then
if [ $VERBOSE -eq 1 ]
then
echo "-- On va maintenant chercher les mails en imap pour checker que tout est bon !";
echo "-- Creation d'un repertoire temporaire /tmp/$KEY";
echo "-- Fichier de conf pour mutt /tmp/$KEY/muttrc";
fi
sleep 5;
[ $VERBOSE -eq 1 ] && echo "-- OK on va y aller ... mais j'attend encore 3 secondes pour donner le temps aux messages d'être traités par les serveurs ...";
sleep 3;
mkdir /tmp/$KEY
echo "set imap_user=$USERFROM
set ssl_force_tls = yes
set ssl_starttls = yes
set imap_pass=$PASSWORD
set folder=imaps://$SERVEUR_TO_TEST:993
set spoolfile = +INBOX
set pipe_decode=yes
set wait_key=no
mailboxes +INBOX
" > /tmp/$KEY/muttrc
[ $VERBOSE -eq 1 ] && echo "-- on télécharge les mails qu'on colle dans un txt";
mutt -F /tmp/$KEY/muttrc -e "push '<limit>~f $KEY<enter><tag-pattern>all<enter><tag-prefix><pipe-message>cat >> /tmp/$KEY/mails.eml<enter><quit>'"
[ $VERBOSE -eq 1 ] && echo "-- Et on fait le ménage sur le serveur";
if [ $KEEP_MAILS_ON_SERVEURS -eq 1 ]
then
[ $VERBOSE -eq 1 ] && echo "-- On les enregistre dans un sous dossier $KEY";
mutt -F /tmp/$KEY/muttrc -e "push '<limit>~f $KEY<enter><tag-pattern>all<enter><tag-prefix><decode-save><enter><enter><quit>y'"
else
[ $VERBOSE -eq 1 ] && echo "-- On supprime les mails identifiés par la clef";
mutt -F /tmp/$KEY/muttrc -e "push '<limit>~f $KEY<enter><delete-pattern>all<enter><enter><quit>y'"
fi
NBTESTS=${#TESTS_DESCRIPTION[@]};
RED='\033[0;31m';
GREEN='\033[0;32m'; # Green
NC='\033[0m'; # No Color
[ $VERBOSE -eq 1 ] && echo "-- On passe les $NBTESTS tests définis dans le repertoire de mails";
echo "-------- RESULTATS DES TESTS ------ ";
for (( i=0; i<${NBTESTS}; i++ ));
do
RESULTCOUNT=$(egrep -c "${TESTS_REGEXP[$i]}" /tmp/$KEY/mails.eml);
[ -z $RESULTCOUNT ] && RESULTCOUNT=0;
if [ $RESULTCOUNT -eq ${TESTS_MATCHING_LINES[$i]} ]
then
echo -e "--$i-- ${TESTS_DESCRIPTION[$i]} : ${GREEN}OK${NC}";
else
echo -e "--$i-- ${TESTS_DESCRIPTION[$i]} : ${RED}KO${NC}";
fi
done
fi