Compare commits
No commits in common. "master" and "develop" have entirely different histories.
74
Dockerfile
74
Dockerfile
@ -1,74 +0,0 @@
|
||||
# docker build -t depollueur . -f ./docker/Dockerfile
|
||||
# two stage building
|
||||
# 1) install compiler and compile filter
|
||||
# 2) copy filter and install postfix
|
||||
# Doxkerfile patern from https://vsupalov.com/cache-docker-build-dependencies-without-volume-mounting/
|
||||
FROM debian as intermediate_depollueur
|
||||
|
||||
########################################
|
||||
RUN apt-get update && apt-get -y autoremove
|
||||
RUN apt-get -y install locales locales-all
|
||||
RUN sed -i '/fr_FR.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
|
||||
ENV LC_ALL fr_FR.UTF-8
|
||||
ENV LANG fr_FR.UTF-8
|
||||
ENV LANGUAGE fr_FR:fr
|
||||
RUN update-locale LANG=fr_FR.UTF-8
|
||||
|
||||
RUN apt-get -y install emacs elpa-php-mode apg
|
||||
RUN apt-get -y install apg dos2unix
|
||||
|
||||
# creation du user filter,son repertoire home, copie des fichiers
|
||||
RUN mkdir /home/filter ; useradd -d /home/filter filter ; chown filter /home/filter
|
||||
########## >>> ce qui suit va être jetté
|
||||
RUN apt-get install -y --fix-missing doxygen git \
|
||||
build-essential make g++ libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libcurl4-gnutls-dev libssl-dev
|
||||
WORKDIR /home/
|
||||
RUN git clone https://git.kaz.bzh/KAZ/depollueur.git
|
||||
WORKDIR /home/depollueur/
|
||||
RUN make
|
||||
RUN cp build/out/* /home/filter/
|
||||
RUN cp src/bash/* /home/filter/
|
||||
########## <<< on ne garde que le répertoire ci-dessous
|
||||
|
||||
##########################################################################
|
||||
# ###################################################################### #
|
||||
# # # #
|
||||
# # On jette tous ce qui est au-dessus pour ne garder que /home/filter # #
|
||||
# # # #
|
||||
# ###################################################################### #
|
||||
##########################################################################
|
||||
|
||||
FROM debian
|
||||
|
||||
########################################
|
||||
RUN apt-get update && apt-get -y autoremove
|
||||
RUN apt-get -y install locales locales-all
|
||||
RUN sed -i '/fr_FR.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
|
||||
ENV LC_ALL fr_FR.UTF-8
|
||||
ENV LANG fr_FR.UTF-8
|
||||
ENV LANGUAGE fr_FR:fr
|
||||
RUN update-locale LANG=fr_FR.UTF-8
|
||||
|
||||
RUN apt-get -y install emacs elpa-php-mode apg
|
||||
RUN apt-get -y install apg dos2unix
|
||||
|
||||
# creation du user filter,son repertoire home, copie des fichiers
|
||||
RUN mkdir /home/filter ; useradd -d /home/filter filter ; chown filter /home/filter
|
||||
########## >>> On fait excatement la même chose que la première fois *
|
||||
RUN apt-get -y install libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libcurl4-gnutls-dev
|
||||
########## pour profiter du cahe des couche de docker
|
||||
COPY --from=intermediate_depollueur /home/filter /home/filter
|
||||
########## <<< mais cette fois on n'installe pas le compilo
|
||||
RUN chown filter /home/filter/*; chmod a+rx /home/filter/*
|
||||
|
||||
# pour le confort : modif du .bashrc de root
|
||||
RUN sed -i 's/# alias/alias/g' /root/.bashrc
|
||||
|
||||
RUN mkdir /var/log/mail ; chmod a+wrx /var/log/mail
|
||||
|
||||
EXPOSE 8080
|
||||
VOLUME [ "/var/log/mail" ]
|
||||
ENTRYPOINT [ "/home/filter/server" ]
|
||||
|
||||
#HEALTHCHECK --interval=10s --timeout=5s --start-period=20s \
|
||||
# CMD XXX || exit 1
|
55
Makefile
55
Makefile
@ -44,23 +44,17 @@ OUT_DIR = $(BLD_DIR)/out
|
||||
LIB_DIR = $(BLD_DIR)/lib
|
||||
OBJ_DIR = $(BLD_DIR)/obj
|
||||
|
||||
EMS_PRG = eMailShrinker
|
||||
EMS_MOD = eMailShrinker EmbeddedData Attachment MainAttachment SizeArg kazDebug kazMisc
|
||||
EMS_SRC = $(patsubst %, $(CPP_DIR)/%.cpp, $(EMS_MOD))
|
||||
EMS_OBJ = $(patsubst %, $(OBJ_DIR)/%.o, $(EMS_MOD))
|
||||
EMS_OUT = $(patsubst %, $(OUT_DIR)/%, $(EMS_PRG))
|
||||
KAZ_PRG = eMailShrinker
|
||||
KAZ_MOD = eMailShrinker EmbeddedData Attachment MainAttachment SizeArg kazDebug kazMisc
|
||||
KAZ_SRC = $(patsubst %, $(CPP_DIR)/%.cpp, $(KAZ_MOD))
|
||||
KAZ_OBJ = $(patsubst %, $(OBJ_DIR)/%.o, $(KAZ_MOD))
|
||||
KAZ_OUT = $(patsubst %, $(OUT_DIR)/%, $(KAZ_PRG))
|
||||
|
||||
SRV_PRG = server
|
||||
SRV_MOD = server kazDebug kazMisc
|
||||
SRV_SRC = $(patsubst %, $(CPP_DIR)/%.cpp, $(SRV_MOD))
|
||||
SRV_OBJ = $(patsubst %, $(OBJ_DIR)/%.o, $(SRV_MOD))
|
||||
SRV_OUT = $(patsubst %, $(OUT_DIR)/%, $(SRV_PRG))
|
||||
|
||||
TSRV_PRG = testServerRW
|
||||
TSRV_MOD = testServerRW kazDebug
|
||||
TSRV_SRC = $(patsubst %, $(CPP_DIR)/%.cpp, $(TSRV_MOD))
|
||||
TSRV_OBJ = $(patsubst %, $(OBJ_DIR)/%.o, $(TSRV_MOD))
|
||||
TSRV_OUT = $(patsubst %, $(OUT_DIR)/%, $(TSRV_PRG))
|
||||
JIR_PRG = jirafeauAPI
|
||||
JIR_MOD = jirafeauAPI SizeArg kazDebug kazMisc
|
||||
JIR_SRC = $(patsubst %, $(CPP_DIR)/%.cpp, $(JIR_MOD))
|
||||
JIR_OBJ = $(patsubst %, $(OBJ_DIR)/%.o, $(JIR_MOD))
|
||||
JIR_OUT = $(patsubst %, $(OUT_DIR)/%, $(JIR_PRG))
|
||||
|
||||
## FLAGS ###############################
|
||||
|
||||
@ -77,28 +71,17 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/*/%.cpp
|
||||
$(CC) $< $(IFLAGS) -cpp -c -o $@
|
||||
|
||||
## ENTRIES #############################
|
||||
all: init $(EMS_PRG) $(SRV_PRG) $(TSRV_PRG) doc
|
||||
all: init eMailShrinker jirafeauAPI
|
||||
|
||||
$(EMS_PRG): $(EMS_OUT)
|
||||
eMailShrinker: $(KAZ_OUT)
|
||||
|
||||
$(EMS_OUT): $(EMS_OBJ)
|
||||
$(CC) $(EMS_OBJ) $(IFLAGS) -cpp -L$(LIB_DIR) $(LFLAGS) -o $@
|
||||
$(KAZ_OUT): $(KAZ_OBJ)
|
||||
$(CC) $(KAZ_OBJ) $(IFLAGS) -cpp -L$(LIB_DIR) $(LFLAGS) -o $@
|
||||
|
||||
$(SRV_PRG): $(SRV_OUT)
|
||||
jirafeauAPI: $(JIR_OUT)
|
||||
|
||||
$(SRV_OUT): $(SRV_OBJ)
|
||||
$(CC) $(SRV_OBJ) $(IFLAGS) -cpp -L$(LIB_DIR) $(LFLAGS) -o $@
|
||||
|
||||
$(TSRV_PRG): $(TSRV_OUT)
|
||||
|
||||
$(TSRV_OUT): $(TSRV_OBJ)
|
||||
$(CC) $(TSRV_OBJ) $(IFLAGS) -cpp -L$(LIB_DIR) $(LFLAGS) -o $@
|
||||
|
||||
image:
|
||||
docker build -t depollueur . -f ./Dockerfile
|
||||
|
||||
doc:
|
||||
doxygen src/Doxyfile
|
||||
$(JIR_OUT): $(JIR_OBJ)
|
||||
$(CC) $(JIR_OBJ) $(IFLAGS) -cpp -L$(LIB_DIR) $(LFLAGS) -o $@
|
||||
|
||||
init:
|
||||
mkdir -p $(OUT_DIR) $(OBJ_DIR) $(LIB_DIR)
|
||||
@ -111,8 +94,8 @@ wipe: clean
|
||||
-rm -rf $(OUT_DIR) $(LIB_DIR) $(BLD_DIR)
|
||||
|
||||
## DEPENDS #############################
|
||||
ALL_OUT = $(EMS_PRG) $(SRV_PRG) $(TSRV_PRG)
|
||||
ALL_OBJ = $(EMS_OBJ) $(SRV_OBJ) $(TSRV_OBJ)
|
||||
ALL_OUT = $(KAZ_PRG) $(JIR_PRG)
|
||||
ALL_OBJ = $(KAZ_OBJ) $(JIR_OBJ)
|
||||
|
||||
DEPENDS = ${ALL_OUT:=.d} ${ALL_OBJ:.o=.d}
|
||||
-include ${DEPENDS}
|
||||
|
@ -13,6 +13,7 @@ depollueur/
|
||||
│ ├── Attachment.cpp
|
||||
│ ├── eMailShrinker.cpp
|
||||
│ ├── EmbeddedData.cpp
|
||||
│ ├── jirafeauAPI.cpp
|
||||
│ ├── kazDebug.cpp
|
||||
│ ├── kazMisc.cpp
|
||||
│ ├── MainAttachment.cpp
|
||||
@ -32,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 doxygen dos2unix
|
||||
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
|
||||
|
||||
git clone https://git.kaz.bzh/KAZ/depollueur.git
|
||||
# or for contributors :
|
||||
|
@ -1,18 +0,0 @@
|
||||
version: '3.3'
|
||||
|
||||
services:
|
||||
|
||||
depollueur:
|
||||
# ports:
|
||||
# - 8088:80
|
||||
image: depollueur
|
||||
container_name: depollueurServ
|
||||
# restart: ${restartPolicy}
|
||||
volumes:
|
||||
- mailLog:/var/log/mail
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
|
||||
volumes:
|
||||
mailLog:
|
||||
# config:
|
2658
src/Doxyfile
2658
src/Doxyfile
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@
|
||||
/*
|
||||
* Kaz addon (see https://git.kaz.bzh/KAZ/depollueur for information)
|
||||
* create un archive for a set of file or update file deadline
|
||||
* version : 2.22 (2024-12-09)
|
||||
|
||||
a.php?r=email => track
|
||||
a.php?p=email => period
|
||||
@ -11,7 +10,7 @@
|
||||
a.php?time=month&key=password + POST file => upload
|
||||
a.php?s=mel@domain.org => form
|
||||
a.php?s=mel@domain.org&t=password + [action] => manage account
|
||||
action: a=login a=logout a=r[on|off] a=p[minute|hour|day|week|month|quarter|semester]
|
||||
action: a=login a=logout a=r[on|off] a=p[minute|hour|day|week|month|quarter]
|
||||
*/
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
@ -26,14 +25,11 @@ require (JIRAFEAU_ROOT . 'lib/functions.php');
|
||||
require (JIRAFEAU_ROOT . 'lib/lang.php');
|
||||
|
||||
define ('VAR_TOKENS', $cfg ['var_root'].'tokens/');
|
||||
define ('VAR_MODE', $cfg ['var_root'].'mode/');
|
||||
define ('VAR_TRACKS', $cfg ['var_root'].'tracks/');
|
||||
define ('VAR_PERIOD', $cfg ['var_root'].'period/');
|
||||
define ('VAR_LANG', $cfg ['var_root'].'lang/');
|
||||
define ('VAR_PERIOD', $cfg ['var_root'].'period/');
|
||||
define ('VAR_FAKE', $cfg ['var_root'].'fake/');
|
||||
define ('VAR_ADMIN', $cfg ['var_root'].'admin/');
|
||||
define ('VAR_CONFIG', $cfg ['var_root'].'config/');
|
||||
define ('FILE_CONFIG', VAR_CONFIG.'default.php');
|
||||
|
||||
$domain="kaz.local";
|
||||
if (preg_match ("%^.*//([^/]*)/?.*$%", $cfg ['web_root'], $matches))
|
||||
@ -43,19 +39,8 @@ define ('MAX_VALID_UPLOAD_TIME', 60);
|
||||
define ('TOKEN_USE_LIMIT', "-2 hours");
|
||||
define ('TOKEN_LOGIN_LIMIT', "-15 minutes");
|
||||
define ('TOKEN_LOGOUT_LIMIT', "-8 hours");
|
||||
if (!file_exists (VAR_CONFIG))
|
||||
mkdir (VAR_CONFIG, 0755);
|
||||
if (!file_exists (FILE_CONFIG)) {
|
||||
file_put_contents (FILE_CONFIG, "<?php".NL.
|
||||
"/* if error with DEFAULT_MODE, DEFAULT_PERIOD or DEFAULT_LANG then remove this file. */".NL.
|
||||
"define ('DEFAULT_MODE', 'footer');".NL.
|
||||
"define ('DEFAULT_PERIOD', 'month');".NL.
|
||||
"define ('DEFAULT_LANG', 'fr');".NL.NL);
|
||||
define ('DEFAULT_MODE', 'footer');
|
||||
define ('DEFAULT_PERIOD', 'month');
|
||||
define ('DEFAULT_LANG', 'fr');
|
||||
} else
|
||||
require (FILE_CONFIG);
|
||||
define ('DEFAULT_PERIOD', "month");
|
||||
define ('DEFAULT_LANG', "fr");
|
||||
|
||||
define ('E_BAD_ARCHIVE_NAME', 'Bad archive name format');
|
||||
define ('E_CREATE_ZIP', "Impossible de créer l'archive.");
|
||||
@ -90,14 +75,13 @@ define ('M_WELCOME', "<p>Informations concernant le compte : <b>___SENDER___</b>
|
||||
define ('M_INCONSISTENT_DATES',
|
||||
" (dates incohéantes avec ___FILENAME___ : ___DIRTIME___ != ___FILETIME___)");
|
||||
|
||||
define ('A_ACTION', 'a'); // action : T_LOGIN, T_LOGOUT, A_MODE(none|footer|attachment|both), A_RECORD+(on|off), A_PERIOD(minute|hour|day|week|month|quarter|semester), A_LANG(fr|en|br)
|
||||
define ('A_ACTION', 'a'); // action : T_LOGIN, T_LOGOUT, A_RECORD+(on|off), A_LANG(fr|en|br), A_PERIOD(minute|hour|day|week|month|quarter)
|
||||
define ('A_GET', 'g'); // get archive
|
||||
define ('A_HASH', 'h'); // file to update or delete
|
||||
define ('A_OPEN_TOKEN', 'o'); // ask token
|
||||
define ('A_SENDER', 's'); // session sender
|
||||
define ('A_TOKEN', 't'); // session token
|
||||
define ('A_UPDATE', 'u'); // update perriod for file or archive
|
||||
define ('A_MODE', 'm'); // get mode status
|
||||
define ('A_RECORD', 'r'); // get track status
|
||||
define ('A_PERIOD', 'p'); // get period status
|
||||
define ('A_LANG', 'l'); // get lang status
|
||||
@ -127,17 +111,15 @@ define ('T_ARCHIVE_TITLE', "archive_content");
|
||||
define ('T_ARCHIVE_MIME', "text/kaz_email_archive");
|
||||
|
||||
|
||||
$modeText = ['none' => "sans", 'footer' => "pied de page", 'attachment' => "pièce jointe", 'both' => "les deux"];
|
||||
$trackText = ['on' => "oui", 'off' => "non"];
|
||||
$periodText = ['minute' => "minute", 'hour' => "heure", 'day' => "jour", 'week' => "semaine", 'month' => "mois", 'quarter' => "trimestre", "semester" => "semestre"];
|
||||
$periodButton = ['hour' => ["🕐", ">1 heure"], // 1F550
|
||||
'day' => ["🕑", ">1 jour"], // 1F551
|
||||
'week' => ["🕒", "> 1 semaine"], // 1F552
|
||||
'month' => ["🕓", "> 1 mois"], // 1F553
|
||||
'quarter' => ["🕔", "> 1 trimestre"], // 1F554
|
||||
'semester' => ["🕕", "> 1 semestre"] // 1F555
|
||||
];
|
||||
$langText = ['fr' => "Francais", 'br' => "Breton", 'en' => "english"];
|
||||
$periodText = ['minute' => "minute", 'hour' => "heure", 'day' => "jour", 'week' => "semaine", 'month' => "mois"];
|
||||
// XXX , 'quarter' => "trimestre"];
|
||||
$periodButton = ['hour' => ["🕕", ">1 heure"],
|
||||
'day' => ["🕜", ">1 jour"],
|
||||
'week' => ["🕝", "> 1 semaine"],
|
||||
'month' => ["🕞", "> 1 mois"]];
|
||||
// XXX 'quarter' => ["🕟", "> 1 trimestre"]];
|
||||
$trackText = ['on' => "oui", 'off' => "non"];
|
||||
$doLogout = '';
|
||||
$message = '';
|
||||
|
||||
@ -148,19 +130,6 @@ $message = '';
|
||||
/* Remove errors. */
|
||||
@error_reporting (0);
|
||||
|
||||
// ========================================
|
||||
if (isset ($_REQUEST [A_MODE]) && !empty ($_REQUEST [A_MODE])) {
|
||||
if (!preg_match ("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/i", $_REQUEST [A_MODE]))
|
||||
$content = DEFAULT_MODE.NL;
|
||||
else
|
||||
$content = getSenderMode ($_REQUEST [A_MODE]).NL;
|
||||
header ('HTTP/1.0 200 OK');
|
||||
header ('Content-Length: ' . strlen ($content));
|
||||
header ('Content-Type: text/plain');
|
||||
echo $content;
|
||||
exit;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
if (isset ($_REQUEST [A_RECORD]) && !empty ($_REQUEST [A_RECORD])) {
|
||||
if (!preg_match ("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/i", $_REQUEST [A_RECORD]))
|
||||
@ -211,6 +180,11 @@ if (isset ($_REQUEST [A_GET]) && !empty ($_REQUEST [A_GET])) {
|
||||
$doDownload = true;
|
||||
}
|
||||
|
||||
$doUpload = false;
|
||||
if (isset ($_FILES ['file'])) {
|
||||
$doUpload = true;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function returnError ($msg) {
|
||||
require (JIRAFEAU_ROOT.'lib/template/header.php');
|
||||
@ -219,34 +193,6 @@ function returnError ($msg) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset ($_FILES ['file'])) {
|
||||
// XXX t ("NoUpload")
|
||||
returnError ("Can't upload file");
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function setSenderMode ($sender, $mode) {
|
||||
if (!$sender)
|
||||
return;
|
||||
if (!file_exists (VAR_MODE))
|
||||
mkdir (VAR_MODE, 0755);
|
||||
if (empty ($mode) || DEFAULT_MODE == $mode) {
|
||||
rmSenderMode ($sender);
|
||||
} else
|
||||
file_put_contents (VAR_MODE.$sender, $mode.NL);
|
||||
}
|
||||
function rmSenderMode ($sender) {
|
||||
if (!$sender)
|
||||
return;
|
||||
if (file_exists (VAR_MODE.$sender))
|
||||
unlink (VAR_MODE.$sender);
|
||||
}
|
||||
function getSenderMode ($sender) {
|
||||
if ($sender && file_exists (VAR_MODE.$sender))
|
||||
return trim (file (VAR_MODE.$sender)[0]);
|
||||
return DEFAULT_MODE;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function setSenderTrack ($sender) {
|
||||
if (!$sender)
|
||||
@ -265,6 +211,29 @@ function isSenderTrack ($sender) {
|
||||
return $sender && file_exists (VAR_TRACKS.$sender);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function setSenderLang ($sender, $lang) {
|
||||
if (!$sender)
|
||||
return;
|
||||
if (!file_exists (VAR_LANG))
|
||||
mkdir (VAR_LANG, 0755);
|
||||
if (empty ($lang) || DEFAULT_LANG == $lang) {
|
||||
rmSenderLang ($sender);
|
||||
} else
|
||||
file_put_contents (VAR_LANG.$sender, $lang.NL);
|
||||
}
|
||||
function rmSenderLang ($sender) {
|
||||
if (!$sender)
|
||||
return;
|
||||
if (file_exists (VAR_LANG.$sender))
|
||||
unlink (VAR_LANG.$sender);
|
||||
}
|
||||
function getSenderLang ($sender) {
|
||||
if ($sender && file_exists (VAR_LANG.$sender))
|
||||
return trim (file (VAR_LANG.$sender)[0]);
|
||||
return DEFAULT_LANG;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function setSenderPeriod ($sender, $period) {
|
||||
if (!$sender)
|
||||
@ -309,9 +278,6 @@ function period2seconds ($periodName) {
|
||||
case 'quarter':
|
||||
return JIRAFEAU_QUARTER;
|
||||
break;
|
||||
case 'semester':
|
||||
return JIRAFEAU_SEMESTER;
|
||||
break;
|
||||
case 'year':
|
||||
return JIRAFEAU_YEAR;
|
||||
break;
|
||||
@ -320,29 +286,6 @@ function period2seconds ($periodName) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function setSenderLang ($sender, $lang) {
|
||||
if (!$sender)
|
||||
return;
|
||||
if (!file_exists (VAR_LANG))
|
||||
mkdir (VAR_LANG, 0755);
|
||||
if (empty ($lang) || DEFAULT_LANG == $lang) {
|
||||
rmSenderLang ($sender);
|
||||
} else
|
||||
file_put_contents (VAR_LANG.$sender, $lang.NL);
|
||||
}
|
||||
function rmSenderLang ($sender) {
|
||||
if (!$sender)
|
||||
return;
|
||||
if (file_exists (VAR_LANG.$sender))
|
||||
unlink (VAR_LANG.$sender);
|
||||
}
|
||||
function getSenderLang ($sender) {
|
||||
if ($sender && file_exists (VAR_LANG.$sender))
|
||||
return trim (file (VAR_LANG.$sender)[0]);
|
||||
return DEFAULT_LANG;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function setSenderFake ($error, $sender, $owner, $dirLink, $fileLink) {
|
||||
global $doLogout;
|
||||
@ -707,6 +650,32 @@ function deleteAction ($linkName) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
if ($doUpload) {
|
||||
$maxtime = time ()+period2seconds ($_REQUEST ['time']);
|
||||
$key = isset ($_REQUEST ['key']) ? $_REQUEST ['key'] : '';
|
||||
$ip = $_SERVER ['HTTP_X_REAL_IP']; // XXX
|
||||
$res = jirafeau_upload (
|
||||
$_FILES['file'],
|
||||
isset ($_POST ['one_time_download']),
|
||||
$key,
|
||||
$maxtime,
|
||||
$ip,
|
||||
$cfg['enable_crypt'],
|
||||
$cfg['link_name_length'],
|
||||
$cfg['file_hash']
|
||||
);
|
||||
if (! count ($res ['error']) || $res['error']['has_error'])
|
||||
$content = 'Error 6 ' . $res['error']['why'];
|
||||
else
|
||||
$content = $res ['link'].NL.$res ['delete_link'].NL;
|
||||
header ('HTTP/1.0 200 OK');
|
||||
header ('Content-Length: ' . strlen ($content));
|
||||
header ('Content-Type: text/plain');
|
||||
echo $content;
|
||||
exit;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
if ($doUpdate) {
|
||||
$maxTime = time ()+period2seconds ($_REQUEST [A_UPDATE]);
|
||||
@ -1007,10 +976,6 @@ if ($doLogout || (isset ($_REQUEST [A_ACTION]) && $_REQUEST [A_ACTION] == T_LOGO
|
||||
if (isset ($_REQUEST [A_ACTION])) {
|
||||
// change track
|
||||
switch (true) {
|
||||
case preg_match ("/^".A_MODE."(".implode ("|", array_keys ($modeText)).")$/i", $_REQUEST [A_ACTION], $matches):
|
||||
setSenderMode ($sender, $matches [1]);
|
||||
$message .= "Votre mode à été mise à jour.";
|
||||
break;
|
||||
case preg_match ("/^".A_RECORD."(on|off)$/i", $_REQUEST [A_ACTION], $matches):
|
||||
if ($matches [1] == "on")
|
||||
setSenderTrack ($sender);
|
||||
@ -1018,14 +983,14 @@ if (isset ($_REQUEST [A_ACTION])) {
|
||||
rmSenderTrack ($sender);
|
||||
$message .= "Votre suivi à été mise à jour.";
|
||||
break;
|
||||
case preg_match ("/^".A_PERIOD."(".implode ("|", array_keys ($periodText)).")$/i", $_REQUEST [A_ACTION], $matches):
|
||||
setSenderPeriod ($sender, $matches [1]);
|
||||
$message .= "Votre période à été mise à jour.";
|
||||
break;
|
||||
case preg_match ("/^".A_LANG."(".implode ("|", array_keys ($langText)).")$/i", $_REQUEST [A_ACTION], $matches):
|
||||
setSenderLang ($sender, $matches [1]);
|
||||
$message .= "Votre lang à été mise à jour.";
|
||||
break;
|
||||
case preg_match ("/^".A_PERIOD."(".implode ("|", array_keys ($periodText)).")$/i", $_REQUEST [A_ACTION], $matches):
|
||||
setSenderPeriod ($sender, $matches [1]);
|
||||
$message .= "Votre période à été mise à jour.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1120,20 +1085,10 @@ div.frame {border: 1px; border-style: solid; padding: 1em; margin: 1em;}
|
||||
--></style>
|
||||
<?php
|
||||
$defaultChecked = [];
|
||||
$defaultChecked [getSenderMode ($sender)] = ' selected="selected"';
|
||||
$defaultChecked [isSenderTrack ($sender) ? "on" : "off"] = ' checked="checked"';
|
||||
$defaultChecked [getSenderPeriod ($sender)] = ' selected="selected"';
|
||||
$defaultChecked [getSenderLang ($sender)] = ' selected="selected"';
|
||||
echo
|
||||
'<form method="post">'.
|
||||
'Je veux que mes futurs envois soient dépollué en plaçant les liens de téléchargements '.
|
||||
'<select name="'.A_ACTION.'" style="width: auto !important;">';
|
||||
foreach ($modeText as $item => $text)
|
||||
echo ' <option value="'.A_MODE.$item.'"'.$defaultChecked [$item].'>'.$text.'</option>';
|
||||
echo
|
||||
'</select> '.
|
||||
'<button type="submit">'."valider".'</button>'.
|
||||
'</form>'.
|
||||
'<form method="post">'.
|
||||
'Je veux que Kaz suive tous mes futurs envois: '.
|
||||
'<input type="hidden" name="'.A_SENDER.'" value="'.$sender.'"/>'.
|
||||
|
@ -1,201 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Jirafeau, your web file repository
|
||||
* Copyright (C) 2008 Julien "axolotl" BERNARD <axolotl@magieeternelle.org>
|
||||
* Copyright (C) 2015 Jerome Jutteau <jerome@jutteau.fr>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default configuration
|
||||
*
|
||||
* To overwrite these settings copy the file,
|
||||
* rename it to »config.local.php« and adapt the parameters.
|
||||
**/
|
||||
|
||||
/* URL of installation, with traling slash (eg. »https://exmaple.com/jirafeau/«)
|
||||
*/
|
||||
$cfg['web_root'] = '';
|
||||
|
||||
/* Path to data directory, with trailing slash (eg. »/var/www/data/var_314159265358979323846264«
|
||||
*/
|
||||
$cfg['var_root'] = '';
|
||||
|
||||
/* Language - choice between 'auto' or any language located in the /lib/locales/ folder.
|
||||
* The mode »auto« will cause the script to detect the user's browser information
|
||||
* and offer a matching language, and use »en« if it is not available.
|
||||
* Forcing to a specific lang lightly reduce lang computation.
|
||||
*/
|
||||
$cfg['lang'] = 'auto';
|
||||
|
||||
/* Select a theme - see media folder for available themes
|
||||
*/
|
||||
$cfg['style'] = 'courgette';
|
||||
|
||||
/* Name the organisation running this installation, eg. 'ACME'
|
||||
*/
|
||||
$cfg['organisation'] = 'ACME';
|
||||
|
||||
/* Provide a contact person for this installation, eg. 'John Doe <doe@example.com>'
|
||||
*/
|
||||
$cfg['contactperson'] = '';
|
||||
|
||||
/* Give the installation a title, eg. 'Datahub' or 'John Doe Filehost'
|
||||
*/
|
||||
$cfg['title'] = '';
|
||||
|
||||
/* Propose a preview link if file type is previewable
|
||||
*/
|
||||
$cfg['preview'] = true;
|
||||
|
||||
/* Enable the encryption feature
|
||||
* By enabling it, file-level deduplication won't work anymore. See FAQ.
|
||||
*/
|
||||
$cfg['enable_crypt'] = false;
|
||||
|
||||
/* Length of link reference
|
||||
*/
|
||||
$cfg['link_name_length'] = 8;
|
||||
|
||||
/* Upload password(s).
|
||||
* An empty array will disable the password authentification.
|
||||
* $cfg['upload_password'] = array(); // No password
|
||||
* $cfg['upload_password'] = array('psw1'); // One password
|
||||
* $cfg['upload_password'] = array('psw1', 'psw2'); // Two passwords
|
||||
*/
|
||||
$cfg['upload_password'] = array();
|
||||
|
||||
/* List of IP allowed to upload a file.
|
||||
* If the list is empty, then there is no upload restriction based on IP.
|
||||
* Elements of the list can be a single IP (e.g. "123.45.67.89") or
|
||||
* an IP range (e.g. "123.45.0.0/16").
|
||||
* Note that CIDR notation is available for IPv4 only for the moment.
|
||||
*/
|
||||
$cfg['upload_ip'] = array();
|
||||
|
||||
/* List of IP allowed to upload a file without password.
|
||||
* Elements of the list can be a single IP (e.g. "123.45.67.89") or
|
||||
* an IP range (e.g. "123.45.0.0/16").
|
||||
* Note that CIDR notation is available for IPv4 only for the moment.
|
||||
*/
|
||||
$cfg['upload_ip_nopassword'] = array();
|
||||
|
||||
/* Password for the admin interface.
|
||||
* An empty password will disable the password authentification.
|
||||
* The password is a sha256 hash of the original version.
|
||||
*/
|
||||
$cfg['admin_password'] = '';
|
||||
|
||||
/* If set, let the user be authenticated as administrator.
|
||||
* The user provided here is the user authenticated by HTTP authentication.
|
||||
* Note that Jirafeau does not manage the HTTP login part, it just checks
|
||||
* that the provided user is logged in.
|
||||
* If »admin_password« parameter is set, then the »admin_password« is ignored.
|
||||
*/
|
||||
$cfg['admin_http_auth_user'] = '';
|
||||
|
||||
/* Allow user to select different options for file expiration time.
|
||||
* Possible values in array:
|
||||
* 'minute': file is available for one minute
|
||||
* 'hour': file available for one hour
|
||||
* 'day': file available for one day
|
||||
* 'week': file available for one week
|
||||
* 'month': file is available for one month
|
||||
* 'quarter': file is available for three months
|
||||
* 'semester': file is available for six months
|
||||
* 'year': file available for one year
|
||||
* 'none': unlimited availability
|
||||
*/
|
||||
$cfg['availabilities'] = array(
|
||||
'minute' => true,
|
||||
'hour' => true,
|
||||
'day' => true,
|
||||
'week' => true,
|
||||
'month' => true,
|
||||
'quarter' => true,
|
||||
'semester' => true,
|
||||
'year' => false,
|
||||
'none' => false
|
||||
);
|
||||
|
||||
/* Set a default value for the expiration time.
|
||||
* The value has to equal one of the enabled options in »availabilities«, e.g. »month«.
|
||||
*/
|
||||
$cfg['availability_default'] = 'month';
|
||||
|
||||
/* Give the uploading user the option to have the file
|
||||
* deleted after the first download.
|
||||
*/
|
||||
$cfg['one_time_download'] = true;
|
||||
|
||||
/* Set maximal upload size expressed in MB.
|
||||
* »0« means unlimited upload size.
|
||||
*/
|
||||
$cfg['maximal_upload_size'] = 0;
|
||||
|
||||
/* Proxy IP
|
||||
* If the installation is behind some reverse proxies, it is possible to set
|
||||
* the allowed proxy IP.
|
||||
* $cfg['proxy_ip'] = array('12.34.56.78');
|
||||
* Jirafeau will then get a visitor's IP from HTTP_X_FORWARDED_FOR
|
||||
* instead of REMOTE_ADDR.
|
||||
*/
|
||||
$cfg['proxy_ip'] = array();
|
||||
|
||||
/* File hash
|
||||
* In order to make file deduplication work, files can be hashed through different methods.
|
||||
* By default, files are hashed through md5 but other methods are available.
|
||||
*
|
||||
* Possible values are 'md5', 'md5_outside' and 'random'.
|
||||
*
|
||||
* With 'md5' option, the whole file is hashed through md5. This is the default.
|
||||
* With 'md5_outside', hash is computed using:
|
||||
* - md5 of the first part of the file,
|
||||
* - md5 of the last part of the file and
|
||||
* - file's size.
|
||||
* This method offer file deduplication at minimal cost but can be dangerous as files with the same partial hash can be mistaken.
|
||||
* With 'random' option, file hash is set to a random value and file deduplication cannot work anymore but it is fast and safe.
|
||||
*/
|
||||
$cfg['file_hash'] = 'md5';
|
||||
|
||||
/* Work around that LiteSpeed truncates large files when downloading.
|
||||
* Only for use with the LiteSpeed web server!
|
||||
* An internal redirect is made using X-LiteSpeed-Location instead
|
||||
* of streaming the file from PHP.
|
||||
* Limitations:
|
||||
* - The Jirafeau files folder has to be placed under the document root and should be
|
||||
* protected from unauthorized access using rewrite rules.
|
||||
* See https://www.litespeedtech.com/support/wiki/doku.php/litespeed_wiki:config:internal-redirect#protection_from_direct_access
|
||||
* - Incompatible with server side encryption.
|
||||
* - Incompatible with one time download.
|
||||
*/
|
||||
$cfg['litespeed_workaround'] = false;
|
||||
|
||||
/* Store uploader's IP along with 'link' file.
|
||||
* Depending of your legislation, you may have to adjust this parameter.
|
||||
*/
|
||||
$cfg['store_uploader_ip'] = true;
|
||||
|
||||
/* Required flag to test if the installation is already installed
|
||||
* or needs to start the installation script
|
||||
*/
|
||||
$cfg['installation_done'] = false;
|
||||
|
||||
/* Enable this debug flag to allow eventual PHP error reporting.
|
||||
* This is disabled by default permission misconfiguration might generate warnings or errors.
|
||||
* Those warnings can break Jirafeau and also show path to var- folder in debug messages.
|
||||
* var- folder should kept secret and accessing it may lead to data leak if unprotected.
|
||||
*/
|
||||
$cfg['debug'] = false;
|
@ -1,119 +0,0 @@
|
||||
{
|
||||
"SIZE_DATA": "Data size",
|
||||
"INCOMPATIBLE_OPTIONS_W": "The following configuration options are incompatible:",
|
||||
"NO_BROWSER_SUPPORT": "Your browser may not support HTML5, so the maximum file size is ",
|
||||
"PLURAL_ENDING": "s",
|
||||
"JI_WEB_RE": "Jirafeau, your web file repository",
|
||||
"SEL_FILE": "Select a file",
|
||||
"SEND": "Send",
|
||||
"UP": "Uploading …",
|
||||
"ONE_TIME_DL": "One-time download",
|
||||
"PSW": "Password",
|
||||
"TIME_LIM": "Time limit",
|
||||
"MAX_FILE_SIZE": "Maximum file size",
|
||||
"POWERED_BY": "powered by the copyleft, libre software project Jirafeau",
|
||||
"MADE_WITH": "Made with",
|
||||
"JI_PROJECT": "Jirafeau Project",
|
||||
"1_MIN": "One minute",
|
||||
"1_H": "One hour",
|
||||
"1_D": "One day",
|
||||
"1_W": "One week",
|
||||
"1_M": "One month",
|
||||
"1_Q": "One quarter",
|
||||
"1_S": "One semester",
|
||||
"1_Y": "One year",
|
||||
"NONE": "None",
|
||||
"UP_PSW": "Upload password",
|
||||
"2_BIG": "The file is too big",
|
||||
"FILE_LIM": "File size limited to",
|
||||
"FILE_DIR_W": "The file directory is not writable.",
|
||||
"LINK_DIR_W": "The link directory is not writable.",
|
||||
"ASYNC_DIR_W": "The async directory is not writable.",
|
||||
"INSTALL_SCRIPT_HERE": "Installer script still present",
|
||||
"ERR_OCC": "An error occurred.",
|
||||
"FILE_UP": "File uploaded.",
|
||||
"DL_PAGE": "Download page",
|
||||
"VALID_UNTIL": "This file is valid until the following date",
|
||||
"VIEW_LINK": "View link",
|
||||
"DIRECT_DL": "Direct download link",
|
||||
"DELETE_LINK": "Delete link",
|
||||
"DL": "Download",
|
||||
"PREVIEW": "Preview",
|
||||
"FILE_404": "Sorry, the requested file is not found",
|
||||
"FILE_NOT_AVAIL": "File not available.",
|
||||
"CONFIRM_DEL": "Confirm deletion",
|
||||
"GONNA_DEL": "You are about to delete",
|
||||
"DELETE": "Delete",
|
||||
"FILE_DELETED": "File has been deleted.",
|
||||
"FILE_EXPIRED": "The time limit of this file has expired.",
|
||||
"PSW_PROTEC": "Password protection",
|
||||
"GIMME_PSW": "Supply password for this file",
|
||||
"ACCESS_KO": "Access denied",
|
||||
"NOW_DOWNLOADING": "You are about to download",
|
||||
"USING_SERVICE": "By using our services, you accept our",
|
||||
"TOS": "Terms of Service",
|
||||
"AUTO_DESTRUCT": "Warning, this file will self-destruct after being read",
|
||||
"INTERNAL_ERROR_DEL": "Internal error during file creation.",
|
||||
"CONF_AUTOGEN_COMMENT": "This file was generated by the installation process. You can edit it. Please see config.original.php to understand the configuration items.",
|
||||
"CANNOT_CREATE_DIR": "The following directory could not be created",
|
||||
"MANUAL_CREATE": "You should create this directory manually.",
|
||||
"DIR_NOT_W": "The following directory is not writable",
|
||||
"GIMME_W": "You should give the write permission to the web server on this directory.",
|
||||
"HERE_SOLUTION": "Here is a solution",
|
||||
"CONF_SOLUTION": "The local configuration file could not be created. Create a <code>lib/config.local.php</code> file and grant write permission to the web server (preferred solution), or grant write permission to the web server in the <code>lib</code> directory.",
|
||||
"CONF_SOLUTION_2": "The local configuration is not writable by the web server. Grant write permission to the web server in the '<code>lib/config.local.php</code>' file.",
|
||||
"JI_INSTALL": "Installation of Jirafeau",
|
||||
"STEP": "step",
|
||||
"OUT_OF": "out of",
|
||||
"ADMIN_PSW": "Admin password",
|
||||
"FINALIZATION": "Finalisation",
|
||||
"SETTING_UP": "Jirafeau is setting up the website according to the configuration you provided.",
|
||||
"PREV_STEP": "Previous step",
|
||||
"RETRY_STEP": "Retry this step",
|
||||
"JI_FONCTIONAL": "Jirafeau is now fully operational",
|
||||
"INFO": "Information",
|
||||
"BASE_ADDR_INFO": "The base address of Jirafeau is the first part of the URL, until (and including) the last slash. For example: \"http://www.example.com/\". Do not forget the trailing slash!",
|
||||
"BASE_ADDR": "Base address",
|
||||
"DATA_DIR_EXPLAINATION": "The data directory is where your files and information about your files will be stored. You should put it outside your website, or at least restrict the access to this directory. Do not forget the trailing slash!",
|
||||
"DATA_DIR": "Data directory",
|
||||
"NEXT_STEP": "Next step",
|
||||
"ADMIN_INTERFACE_INFO": "Jirafeau has an admin interface (through admin.php). You can set a password to access the interface or leave it empty to disable the interface.",
|
||||
"NO_ADMIN": "Sorry, the admin interface is not enabled.",
|
||||
"NO_ADMIN_AUTH": "Sorry, you have not logged onto the admin interface.",
|
||||
"LOGIN": "Login",
|
||||
"BAD_PSW": "Wrong password.",
|
||||
"ADMIN_INTERFACE": "Admin interface",
|
||||
"CLEAN_EXPIRED": "Clean expired files",
|
||||
"CLEAN_INCOMPLETE": "Clean old unfinished transfers",
|
||||
"CLEAN": "Clean",
|
||||
"SEARCH_NAME": "Search for files by name",
|
||||
"SEARCH": "Search",
|
||||
"LS_FILES": "List all files",
|
||||
"LIST": "List",
|
||||
"ACTIONS": "Actions",
|
||||
"SEARH_BY_HASH": "Search for files by file hash",
|
||||
"SEARCH_LINK": "Search a specific link",
|
||||
"CLEANED_FILES_CNT": "Number of cleaned files",
|
||||
"LOGOUT": "Log out",
|
||||
"NOW_LOGOUT": "You are now logged out",
|
||||
"LINK_DELETED": "Link deleted",
|
||||
"FILENAME": "Filename",
|
||||
"FILE": "file",
|
||||
"LINK": "link",
|
||||
"TYPE": "Type",
|
||||
"SIZE": "Size",
|
||||
"EXPIRE": "Expire",
|
||||
"ONETIME": "One-time",
|
||||
"UPLOAD_DATE": "Upload date",
|
||||
"ORIGIN": "Origin",
|
||||
"ACTION": "Action",
|
||||
"DEL_LINK": "Del link",
|
||||
"DEL_FILE_LINKS": "Del file and links",
|
||||
"DELETED_LINKS": "Deleted links",
|
||||
"YEAR": "year",
|
||||
"DAY": "day",
|
||||
"MINUTE": "minute",
|
||||
"HOUR": "hour",
|
||||
"SECOND": "second",
|
||||
"LESS_1_SEC": "less than a second"
|
||||
}
|
@ -89,8 +89,6 @@ if (!empty($delete_code) && $delete_code == $link['link_code']) {
|
||||
'</p></div>';
|
||||
} else { ?>
|
||||
<div>
|
||||
<form action="<?php echo 'f.php?h=' . $link_name . '&d=' . $delete_code; ?>" method="post" id="submit_delete_post" class="form login">
|
||||
<input type="hidden" name="do_delete" value="1" />
|
||||
<form action="f.php" method="post" id="submit_delete_post" class="form login">
|
||||
<input type="hidden" name="do_delete" value=1/>
|
||||
<fieldset>
|
||||
@ -99,15 +97,17 @@ if (!empty($delete_code) && $delete_code == $link['link_code']) {
|
||||
<tr><td>
|
||||
<?php echo t('GONNA_DEL') . ' "' . jirafeau_escape($link['file_name']) . '" (' . jirafeau_human_size($link['file_size']) . ').' ?>
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<tr><td>
|
||||
<?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'); ?>"
|
||||
</td></tr>
|
||||
</table>
|
||||
</fieldset></form></div><?php
|
||||
}
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<input type="submit" id="submit_delete" value="<?php echo t('DELETE'); ?>"
|
||||
<?php $action_delete="'f.php?h=' . $link_name . '&d=' . $delete_code'; document.getElementById('submit_delete').submit ();"; ?>
|
||||
onclick="document.getElementById('submit_delete_post').action='<?php echo $action_delete; ?>" />
|
||||
</td></tr>
|
||||
</table>
|
||||
</fieldset></form></div><?php
|
||||
}
|
||||
require(JIRAFEAU_ROOT.'lib/template/footer.php');
|
||||
exit;
|
||||
}
|
||||
@ -145,7 +145,7 @@ if (!empty($link['key'])) {
|
||||
'<legend>' . t('PSW_PROTEC') .
|
||||
'</legend><table><tr><td>' .
|
||||
t('GIMME_PSW') . ' : ' .
|
||||
'<input type = "password" name = "key" autocomplete = "current-password"/>' .
|
||||
'<input type = "password" name = "key" />' .
|
||||
'</td></tr>' .
|
||||
'<tr><td>' .
|
||||
t('USING_SERVICE'). ' <a href="tos.php" target="_blank" rel="noopener noreferrer">' . t('TOS') . '</a>.' .
|
||||
@ -276,16 +276,11 @@ elseif ($link['crypted']) {
|
||||
}
|
||||
/* Read file. */
|
||||
else {
|
||||
if ($cfg['use_xsendfile']) {
|
||||
$file_web_path = preg_replace('#^' . $_SERVER['DOCUMENT_ROOT'] . '#', '', VAR_FILES);
|
||||
header('X-Sendfile: ' . $file_web_path . $p . $link['hash']);
|
||||
} else {
|
||||
$r = fopen(VAR_FILES . $p . $link['hash'], 'r');
|
||||
while (!feof($r)) {
|
||||
print fread($r, 1024);
|
||||
}
|
||||
fclose($r);
|
||||
$r = fopen(VAR_FILES . $p . $link['hash'], 'r');
|
||||
while (!feof($r)) {
|
||||
print fread($r, 1024);
|
||||
}
|
||||
fclose($r);
|
||||
}
|
||||
|
||||
if ($link['onetime'] == 'O') {
|
||||
|
@ -1,791 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Jirafeau, your web file repository
|
||||
* Copyright (C) 2015 Jerome Jutteau <jerome@jutteau.fr>
|
||||
* Copyright (C) 2015 Nicola Spanti (RyDroid) <dev@nicola-spanti.info>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
header('Content-Type: text/javascript');
|
||||
define('JIRAFEAU_ROOT', dirname(__FILE__) . '/../');
|
||||
|
||||
require(JIRAFEAU_ROOT . 'lib/settings.php');
|
||||
require(JIRAFEAU_ROOT . 'lib/functions.php');
|
||||
require(JIRAFEAU_ROOT . 'lib/lang.php');
|
||||
?>
|
||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
var web_root = "<?php echo $cfg['web_root']; ?>";
|
||||
|
||||
var lang_array = <?php echo json_lang_generator(null); ?>;
|
||||
var lang_array_fallback = <?php echo json_lang_generator("en"); ?>;
|
||||
|
||||
function translate (expr) {
|
||||
if (lang_array.hasOwnProperty(expr)) {
|
||||
var e = lang_array[expr];
|
||||
if (!isEmpty(e))
|
||||
return e;
|
||||
}
|
||||
if (lang_array_fallback.hasOwnProperty(expr)) {
|
||||
var e = lang_array_fallback[expr];
|
||||
if (!isEmpty(e))
|
||||
return e;
|
||||
}
|
||||
return "FIXME: " + expr;
|
||||
}
|
||||
|
||||
function isEmpty(str) {
|
||||
return (!str || 0 === str.length);
|
||||
}
|
||||
|
||||
// Extend date object with format method
|
||||
Date.prototype.format = function(format) {
|
||||
format = format || 'YYYY-MM-DD hh:mm';
|
||||
|
||||
var zeropad = function(number, length) {
|
||||
number = number.toString();
|
||||
length = length || 2;
|
||||
while(number.length < length)
|
||||
number = '0' + number;
|
||||
return number;
|
||||
},
|
||||
formats = {
|
||||
YYYY: this.getFullYear(),
|
||||
MM: zeropad(this.getMonth() + 1),
|
||||
DD: zeropad(this.getDate()),
|
||||
hh: zeropad(this.getHours()),
|
||||
mm: zeropad(this.getMinutes()),
|
||||
O: (function() {
|
||||
localDate = new Date;
|
||||
sign = (localDate.getTimezoneOffset() > 0) ? '-' : '+';
|
||||
offset = Math.abs(localDate.getTimezoneOffset());
|
||||
hours = zeropad(Math.floor(offset / 60));
|
||||
minutes = zeropad(offset % 60);
|
||||
return sign + hours + ":" + minutes;
|
||||
})()
|
||||
},
|
||||
pattern = '(' + Object.keys(formats).join(')|(') + ')';
|
||||
|
||||
return format.replace(new RegExp(pattern, 'g'), function(match) {
|
||||
return formats[match];
|
||||
});
|
||||
};
|
||||
|
||||
function dateFromUtcString(datestring) {
|
||||
// matches »YYYY-MM-DD hh:mm«
|
||||
var m = datestring.match(/(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)/);
|
||||
return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], 0));
|
||||
}
|
||||
|
||||
function dateFromUtcTimestamp(datetimestamp) {
|
||||
return new Date(parseInt(datetimestamp) * 1000)
|
||||
}
|
||||
|
||||
function dateToUtcString(datelocal) {
|
||||
return new Date(
|
||||
datelocal.getUTCFullYear(),
|
||||
datelocal.getUTCMonth(),
|
||||
datelocal.getUTCDate(),
|
||||
datelocal.getUTCHours(),
|
||||
datelocal.getUTCMinutes(),
|
||||
datelocal.getUTCSeconds()
|
||||
).format();
|
||||
}
|
||||
|
||||
function dateToUtcTimestamp(datelocal) {
|
||||
return (Date.UTC(
|
||||
datelocal.getUTCFullYear(),
|
||||
datelocal.getUTCMonth(),
|
||||
datelocal.getUTCDate(),
|
||||
datelocal.getUTCHours(),
|
||||
datelocal.getUTCMinutes(),
|
||||
datelocal.getUTCSeconds()
|
||||
) / 1000);
|
||||
}
|
||||
|
||||
function convertAllDatetimeFields() {
|
||||
datefields = document.getElementsByClassName('datetime')
|
||||
for(var i=0; i<datefields.length; i++) {
|
||||
dateUTC = datefields[i].getAttribute('data-datetime');
|
||||
datefields[i].setAttribute('title', dateUTC + ' (GMT)');
|
||||
datefields[i].innerHTML = dateFromUtcString(dateUTC).format('YYYY-MM-DD hh:mm (GMT O)');
|
||||
}
|
||||
}
|
||||
|
||||
function show_link (reference, delete_code, crypt_key, date)
|
||||
{
|
||||
// Upload finished
|
||||
document.getElementById('uploading').style.display = 'none';
|
||||
document.getElementById('upload').style.display = 'none';
|
||||
document.getElementById('upload_finished').style.display = '';
|
||||
document.title = "100% - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
|
||||
|
||||
// Download page
|
||||
var download_link_href = 'f.php?h=' + reference;
|
||||
if (crypt_key.length > 0)
|
||||
{
|
||||
download_link_href += '&k=' + crypt_key;
|
||||
}
|
||||
if (!!document.getElementById('upload_finished_download_page'))
|
||||
{
|
||||
document.getElementById('upload_link').href = download_link_href;
|
||||
document.getElementById('upload_link_text').innerHTML = web_root + download_link_href;
|
||||
}
|
||||
|
||||
// Email link
|
||||
var filename = document.getElementById('file_select').files[0].name;
|
||||
var b = encodeURIComponent("<?php echo t("DL"); ?> \"" + filename + "\":") + "%0D" + "%0A";
|
||||
b += encodeURIComponent(web_root + download_link_href) + "%0D" + "%0A";
|
||||
if (false == isEmpty(date))
|
||||
{
|
||||
b += "%0D" + "%0A" + encodeURIComponent("<?php echo t("VALID_UNTIL"); ?>: " + date.format('YYYY-MM-DD hh:mm (GMT O)')) + "%0D" + "%0A";
|
||||
document.getElementById('upload_link_email').href = "mailto:?body=" + b + "&subject=" + encodeURIComponent(filename);
|
||||
}
|
||||
|
||||
// Delete link
|
||||
var delete_link_href = 'f.php?h=' + reference + '&d=' + delete_code;
|
||||
document.getElementById('delete_link').href = delete_link_href;
|
||||
document.getElementById('delete_link_text').innerHTML = web_root + delete_link_href;
|
||||
|
||||
// Validity date
|
||||
if (isEmpty(date))
|
||||
{
|
||||
document.getElementById('date').style.display = 'none';
|
||||
}
|
||||
else {
|
||||
document.getElementById('date').innerHTML = '<span class="datetime" title="'
|
||||
+ dateToUtcString(date) + ' (GMT)">'
|
||||
+ date.format('YYYY-MM-DD hh:mm (GMT O)')
|
||||
+ '</span>';
|
||||
document.getElementById('date').style.display = '';
|
||||
}
|
||||
|
||||
// Preview link (if allowed)
|
||||
if (!!document.getElementById('preview_link'))
|
||||
{
|
||||
document.getElementById('upload_finished_preview').style.display = 'none';
|
||||
var preview_link_href = 'f.php?h=' + reference + '&p=1';
|
||||
if (crypt_key.length > 0)
|
||||
{
|
||||
preview_link_href += '&k=' + crypt_key;
|
||||
}
|
||||
|
||||
// Test if content can be previewed
|
||||
type = document.getElementById('file_select').files[0].type;
|
||||
if (type.indexOf("image") > -1 ||
|
||||
type.indexOf("audio") > -1 ||
|
||||
type.indexOf("text") > -1 ||
|
||||
type.indexOf("video") > -1)
|
||||
{
|
||||
document.getElementById('preview_link').href = preview_link_href;
|
||||
document.getElementById('preview_link_text').innerHTML = web_root + preview_link_href;
|
||||
document.getElementById('upload_finished_preview').style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Direct download link
|
||||
var direct_download_link_href = 'f.php?h=' + reference + '&d=1';
|
||||
if (crypt_key.length > 0)
|
||||
{
|
||||
direct_download_link_href += '&k=' + crypt_key;
|
||||
}
|
||||
document.getElementById('direct_link').href = direct_download_link_href;
|
||||
document.getElementById('direct_link_text').innerHTML = web_root + direct_download_link_href;
|
||||
|
||||
// Hide preview and direct download link if password is set
|
||||
if (document.getElementById('input_key').value.length > 0)
|
||||
{
|
||||
if (!!document.getElementById('preview_link'))
|
||||
document.getElementById('upload_finished_preview').style.display = 'none';
|
||||
document.getElementById('upload_direct_download').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function show_upload_progression (percentage, speed, time_left)
|
||||
{
|
||||
document.getElementById('uploaded_percentage').innerHTML = percentage;
|
||||
document.getElementById('uploaded_speed').innerHTML = speed;
|
||||
document.getElementById('uploaded_time').innerHTML = time_left;
|
||||
document.title = percentage + " - <?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
|
||||
}
|
||||
|
||||
function hide_upload_progression ()
|
||||
{
|
||||
document.getElementById('uploaded_percentage').style.display = 'none';
|
||||
document.getElementById('uploaded_speed').style.display = 'none';
|
||||
document.getElementById('uploaded_time').style.display = 'none';
|
||||
document.title = "<?php echo empty($cfg['title']) ? 'Jirafeau' : $cfg['title']; ?>";
|
||||
}
|
||||
|
||||
function upload_progress (e)
|
||||
{
|
||||
if (e == undefined || e == null || !e.lengthComputable)
|
||||
return;
|
||||
|
||||
// Init time estimation if needed
|
||||
if (upload_time_estimation_total_size == 0)
|
||||
upload_time_estimation_total_size = e.total;
|
||||
|
||||
// Compute percentage
|
||||
var p = Math.round (e.loaded * 100 / e.total);
|
||||
var p_str = ' ';
|
||||
if (p != 100)
|
||||
p_str = p.toString() + '%';
|
||||
// Update estimation speed
|
||||
upload_time_estimation_add(e.loaded);
|
||||
// Get speed string
|
||||
var speed_str = upload_time_estimation_speed_string();
|
||||
speed_str = upload_speed_refresh_limiter(speed_str);
|
||||
// Get time string
|
||||
var time_str = chrono_update(upload_time_estimation_time());
|
||||
|
||||
show_upload_progression (p_str, speed_str, time_str);
|
||||
}
|
||||
|
||||
function control_selected_file_size(max_size, error_str)
|
||||
{
|
||||
f_size = document.getElementById('file_select').files[0].size;
|
||||
if (max_size > 0 && f_size > max_size * 1024 * 1024)
|
||||
{
|
||||
pop_failure(error_str);
|
||||
document.getElementById('send').style.display = 'none';
|
||||
}
|
||||
else
|
||||
{
|
||||
// add class to restyle upload form in next step
|
||||
document.getElementById('upload').setAttribute('class', 'file-selected');
|
||||
// display options
|
||||
document.getElementById('options').style.display = 'block';
|
||||
document.getElementById('send').style.display = 'block';
|
||||
document.getElementById('error_pop').style.display = 'none';
|
||||
document.getElementById('send').focus();
|
||||
}
|
||||
}
|
||||
|
||||
function XHRErrorHandler(e)
|
||||
{
|
||||
var text = "${e.type}: ${e.loaded} bytes transferred"
|
||||
console.log(text)
|
||||
}
|
||||
|
||||
function pop_failure (e)
|
||||
{
|
||||
var text = "<p>An error occured";
|
||||
if (typeof e !== 'undefined')
|
||||
text += ": " + e;
|
||||
text += "</p>";
|
||||
document.getElementById('error_pop').innerHTML = e;
|
||||
|
||||
document.getElementById('uploading').style.display = 'none';
|
||||
document.getElementById('error_pop').style.display = '';
|
||||
document.getElementById('upload').style.display = '';
|
||||
document.getElementById('send').style.display = '';
|
||||
}
|
||||
|
||||
function add_time_string_to_date(d, time)
|
||||
{
|
||||
if(typeof(d) != 'object' || !(d instanceof Date))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (time == 'minute')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 60);
|
||||
return true;
|
||||
}
|
||||
if (time == 'hour')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 3600);
|
||||
return true;
|
||||
}
|
||||
if (time == 'day')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 86400);
|
||||
return true;
|
||||
}
|
||||
if (time == 'week')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 604800);
|
||||
return true;
|
||||
}
|
||||
if (time == 'month')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 2592000);
|
||||
return true;
|
||||
}
|
||||
if (time == 'quarter')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 7776000);
|
||||
return true;
|
||||
}
|
||||
if (time == 'semester')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 110678400);
|
||||
return true;
|
||||
}
|
||||
if (time == 'year')
|
||||
{
|
||||
d.setSeconds (d.getSeconds() + 31536000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function classic_upload (file, time, password, one_time, upload_password)
|
||||
{
|
||||
// Delay time estimation init as we can't have file size
|
||||
upload_time_estimation_init(0);
|
||||
|
||||
var req = new XMLHttpRequest ();
|
||||
req.upload.addEventListener ("progress", upload_progress, false);
|
||||
req.addEventListener ("error", XHRErrorHandler, false);
|
||||
req.addEventListener ("abort", XHRErrorHandler, false);
|
||||
req.onreadystatechange = function ()
|
||||
{
|
||||
if (req.readyState == 4 && req.status == 200)
|
||||
{
|
||||
var res = req.responseText;
|
||||
|
||||
// if response starts with "Error" then show a failure
|
||||
if (/^Error/.test(res))
|
||||
{
|
||||
pop_failure (res);
|
||||
return;
|
||||
}
|
||||
|
||||
res = res.split ("\n");
|
||||
var expiryDate = '';
|
||||
if (time != 'none')
|
||||
{
|
||||
// convert time (local time + selected expiry date)
|
||||
var localDatetime = new Date();
|
||||
if(!add_time_string_to_date(localDatetime, time))
|
||||
{
|
||||
pop_failure ('Error: Date can not be parsed');
|
||||
return;
|
||||
}
|
||||
expiryDate = localDatetime;
|
||||
}
|
||||
|
||||
show_link (res[0], res[1], res[2], expiryDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
pop_failure ("<?php echo t("ERR_OCC"); ?>");
|
||||
}
|
||||
}
|
||||
req.open ("POST", 'script.php' , true);
|
||||
|
||||
var form = new FormData();
|
||||
form.append ("file", file);
|
||||
if (time)
|
||||
form.append ("time", time);
|
||||
if (password)
|
||||
form.append ("key", password);
|
||||
if (one_time)
|
||||
form.append ("one_time_download", '1');
|
||||
if (upload_password.length > 0)
|
||||
form.append ("upload_password", upload_password);
|
||||
|
||||
req.send (form);
|
||||
}
|
||||
|
||||
function check_html5_file_api ()
|
||||
{
|
||||
return window.File && window.FileReader && window.FileList && window.Blob;
|
||||
}
|
||||
|
||||
var async_global_transfered = 0;
|
||||
var async_global_file;
|
||||
var async_global_ref = '';
|
||||
var async_global_max_size = 0;
|
||||
var async_global_time;
|
||||
var async_global_transfering = 0;
|
||||
var async_global_last_code;
|
||||
|
||||
function async_upload_start (max_size, file, time, password, one_time, upload_password)
|
||||
{
|
||||
async_global_transfered = 0;
|
||||
async_global_file = file;
|
||||
async_global_max_size = max_size;
|
||||
async_global_time = time;
|
||||
|
||||
var req = new XMLHttpRequest ();
|
||||
req.addEventListener ("error", XHRErrorHandler, false);
|
||||
req.addEventListener ("abort", XHRErrorHandler, false);
|
||||
req.onreadystatechange = function ()
|
||||
{
|
||||
if (req.readyState == 4 && req.status == 200)
|
||||
{
|
||||
var res = req.responseText;
|
||||
|
||||
if (/^Error/.test(res))
|
||||
{
|
||||
pop_failure (res);
|
||||
return;
|
||||
}
|
||||
|
||||
res = res.split ("\n");
|
||||
async_global_ref = res[0];
|
||||
var code = res[1];
|
||||
async_upload_push (code);
|
||||
}
|
||||
}
|
||||
req.open ("POST", 'script.php?init_async' , true);
|
||||
|
||||
var form = new FormData();
|
||||
form.append ("filename", async_global_file.name);
|
||||
form.append ("type", async_global_file.type);
|
||||
if (time)
|
||||
form.append ("time", time);
|
||||
if (password)
|
||||
form.append ("key", password);
|
||||
if (one_time)
|
||||
form.append ("one_time_download", '1');
|
||||
if (upload_password.length > 0)
|
||||
form.append ("upload_password", upload_password);
|
||||
|
||||
// Start time estimation
|
||||
upload_time_estimation_init(async_global_file.size);
|
||||
|
||||
req.send (form);
|
||||
}
|
||||
|
||||
function async_upload_progress (e)
|
||||
{
|
||||
if (e == undefined || e == null || !e.lengthComputable && async_global_file.size != 0)
|
||||
return;
|
||||
|
||||
// Compute percentage
|
||||
var p = Math.round ((e.loaded + async_global_transfered) * 100 / (async_global_file.size));
|
||||
var p_str = ' ';
|
||||
if (p != 100)
|
||||
p_str = p.toString() + '%';
|
||||
// Update estimation speed
|
||||
upload_time_estimation_add(e.loaded + async_global_transfered);
|
||||
// Get speed string
|
||||
var speed_str = upload_time_estimation_speed_string();
|
||||
speed_str = upload_speed_refresh_limiter(speed_str);
|
||||
// Get time string
|
||||
var time_str = chrono_update(upload_time_estimation_time());
|
||||
|
||||
show_upload_progression (p_str, speed_str, time_str);
|
||||
}
|
||||
|
||||
function async_upload_push (code)
|
||||
{
|
||||
async_global_last_code = code;
|
||||
if (async_global_transfered == async_global_file.size)
|
||||
{
|
||||
hide_upload_progression ();
|
||||
async_upload_end (code);
|
||||
return;
|
||||
}
|
||||
var req = new XMLHttpRequest ();
|
||||
req.upload.addEventListener ("progress", async_upload_progress, false);
|
||||
req.addEventListener ("error", XHRErrorHandler, false);
|
||||
req.addEventListener ("abort", XHRErrorHandler, false);
|
||||
req.onreadystatechange = function ()
|
||||
{
|
||||
if (req.readyState == 4)
|
||||
{
|
||||
if (req.status == 200)
|
||||
{
|
||||
var res = req.responseText;
|
||||
|
||||
// This error may be triggered when Jirafeau does not receive any file in POST.
|
||||
// This may be due to bad php configuration where post_max_size is too low
|
||||
// comparing to upload_max_filesize. Let's retry with lower file size.
|
||||
if (res === "Error 23")
|
||||
{
|
||||
async_global_max_size = Math.max(1, async_global_max_size - 500);
|
||||
async_upload_push (async_global_last_code);
|
||||
return;
|
||||
}
|
||||
else if (/^Error/.test(res))
|
||||
{
|
||||
pop_failure (res);
|
||||
return;
|
||||
}
|
||||
|
||||
res = res.split ("\n");
|
||||
var code = res[0]
|
||||
async_global_transfered = async_global_transfering;
|
||||
async_upload_push (code);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (req.status == 413) // Request Entity Too Large
|
||||
{
|
||||
// lower async_global_max_size and retry
|
||||
async_global_max_size = Math.max(1, parseInt (async_global_max_size * 0.8));
|
||||
}
|
||||
async_upload_push (async_global_last_code);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
req.open ("POST", 'script.php?push_async' , true);
|
||||
|
||||
var start = async_global_transfered;
|
||||
var end = start + async_global_max_size;
|
||||
if (end >= async_global_file.size)
|
||||
end = async_global_file.size;
|
||||
var blob = async_global_file.slice (start, end);
|
||||
async_global_transfering = end;
|
||||
|
||||
var form = new FormData();
|
||||
form.append ("ref", async_global_ref);
|
||||
form.append ("data", blob);
|
||||
form.append ("code", code);
|
||||
req.send (form);
|
||||
}
|
||||
|
||||
function async_upload_end (code)
|
||||
{
|
||||
var req = new XMLHttpRequest ();
|
||||
req.addEventListener ("error", XHRErrorHandler, false);
|
||||
req.addEventListener ("abort", XHRErrorHandler, false);
|
||||
req.onreadystatechange = function ()
|
||||
{
|
||||
if (req.readyState == 4 && req.status == 200)
|
||||
{
|
||||
var res = req.responseText;
|
||||
|
||||
if (/^Error/.test(res))
|
||||
{
|
||||
pop_failure (res);
|
||||
return;
|
||||
}
|
||||
|
||||
res = res.split ("\n");
|
||||
var expiryDate = '';
|
||||
if (async_global_time != 'none')
|
||||
{
|
||||
// convert time (local time + selected expiry date)
|
||||
var localDatetime = new Date();
|
||||
if(!add_time_string_to_date(localDatetime, async_global_time)) {
|
||||
pop_failure ('Error: Date can not be parsed');
|
||||
return;
|
||||
}
|
||||
expiryDate = localDatetime;
|
||||
}
|
||||
|
||||
show_link (res[0], res[1], res[2], expiryDate);
|
||||
}
|
||||
}
|
||||
req.open ("POST", 'script.php?end_async' , true);
|
||||
|
||||
var form = new FormData();
|
||||
form.append ("ref", async_global_ref);
|
||||
form.append ("code", code);
|
||||
req.send (form);
|
||||
}
|
||||
|
||||
function upload (max_size)
|
||||
{
|
||||
var one_time_checkbox = document.getElementById('one_time_download');
|
||||
var one_time = one_time_checkbox !== null ? one_time_checkbox.checked : false;
|
||||
if (check_html5_file_api ())
|
||||
{
|
||||
async_upload_start (
|
||||
max_size,
|
||||
document.getElementById('file_select').files[0],
|
||||
document.getElementById('select_time').value,
|
||||
document.getElementById('input_key').value,
|
||||
one_time,
|
||||
document.getElementById('upload_password').value
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
classic_upload (
|
||||
document.getElementById('file_select').files[0],
|
||||
document.getElementById('select_time').value,
|
||||
document.getElementById('input_key').value,
|
||||
one_time,
|
||||
document.getElementById('upload_password').value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var upload_time_estimation_total_size = 42;
|
||||
var upload_time_estimation_transfered_size = 42;
|
||||
var upload_time_estimation_transfered_date = 42;
|
||||
var upload_time_estimation_moving_average_speed = 42;
|
||||
|
||||
function upload_time_estimation_init(total_size)
|
||||
{
|
||||
upload_time_estimation_total_size = total_size;
|
||||
upload_time_estimation_transfered_size = 0;
|
||||
upload_time_estimation_moving_average_speed = 0;
|
||||
var d = new Date();
|
||||
upload_time_estimation_transfered_date = d.getTime();
|
||||
}
|
||||
|
||||
function upload_time_estimation_add(total_transfered_size)
|
||||
{
|
||||
// Let's compute the current speed
|
||||
var d = new Date();
|
||||
var speed = upload_time_estimation_moving_average_speed;
|
||||
if (d.getTime() - upload_time_estimation_transfered_date != 0)
|
||||
speed = (total_transfered_size - upload_time_estimation_transfered_size)
|
||||
/ (d.getTime() - upload_time_estimation_transfered_date);
|
||||
// Let's compute moving average speed on 30 values
|
||||
var m = (upload_time_estimation_moving_average_speed * 29 + speed) / 30;
|
||||
// Update global values
|
||||
upload_time_estimation_transfered_size = total_transfered_size;
|
||||
upload_time_estimation_transfered_date = d.getTime();
|
||||
upload_time_estimation_moving_average_speed = m;
|
||||
}
|
||||
|
||||
function upload_time_estimation_speed_string()
|
||||
{
|
||||
// speed ms -> s
|
||||
var s = upload_time_estimation_moving_average_speed * 1000;
|
||||
var res = 0;
|
||||
var scale = '';
|
||||
if (s <= 1000)
|
||||
{
|
||||
res = s.toString();
|
||||
scale = "B/s";
|
||||
}
|
||||
else if (s < 1000000)
|
||||
{
|
||||
res = Math.floor(s/100) / 10;
|
||||
scale = "KB/s";
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Math.floor(s/100000) / 10;
|
||||
scale = "MB/s";
|
||||
}
|
||||
if (res == 0)
|
||||
return '';
|
||||
return res.toString() + ' ' + scale;
|
||||
}
|
||||
|
||||
function milliseconds_to_time_string (milliseconds)
|
||||
{
|
||||
function numberEnding (number) {
|
||||
return (number > 1) ? translate ('PLURAL_ENDING') : '';
|
||||
}
|
||||
|
||||
var temp = Math.floor(milliseconds / 1000);
|
||||
var years = Math.floor(temp / 31536000);
|
||||
if (years) {
|
||||
return years + ' ' + translate ('YEAR') + numberEnding(years);
|
||||
}
|
||||
var days = Math.floor((temp %= 31536000) / 86400);
|
||||
if (days) {
|
||||
return days + ' ' + translate ('DAY') + numberEnding(days);
|
||||
}
|
||||
var hours = Math.floor((temp %= 86400) / 3600);
|
||||
if (hours) {
|
||||
return hours + ' ' + translate ('HOUR') + numberEnding(hours);
|
||||
}
|
||||
var minutes = Math.floor((temp %= 3600) / 60);
|
||||
if (minutes) {
|
||||
return minutes + ' ' + translate ('MINUTE') + numberEnding(minutes);
|
||||
}
|
||||
var seconds = temp % 60;
|
||||
if (seconds) {
|
||||
return seconds + ' ' + translate ('SECOND') + numberEnding(seconds);
|
||||
}
|
||||
return translate ('LESS_1_SEC');
|
||||
}
|
||||
|
||||
function upload_time_estimation_time()
|
||||
{
|
||||
// Estimate remaining time
|
||||
if (upload_time_estimation_moving_average_speed == 0)
|
||||
return 0;
|
||||
return (upload_time_estimation_total_size - upload_time_estimation_transfered_size)
|
||||
/ upload_time_estimation_moving_average_speed;
|
||||
}
|
||||
|
||||
var chrono_last_update = 0;
|
||||
var chrono_time_ms = 0;
|
||||
var chrono_time_ms_last_update = 0;
|
||||
function chrono_update(time_ms)
|
||||
{
|
||||
var d = new Date();
|
||||
var chrono = 0;
|
||||
// Don't update too often
|
||||
if (d.getTime() - chrono_last_update < 3000 &&
|
||||
chrono_time_ms_last_update > 0)
|
||||
chrono = chrono_time_ms;
|
||||
else
|
||||
{
|
||||
chrono_last_update = d.getTime();
|
||||
chrono_time_ms = time_ms;
|
||||
chrono = time_ms;
|
||||
chrono_time_ms_last_update = d.getTime();
|
||||
}
|
||||
|
||||
// Adjust chrono for smooth estimation
|
||||
chrono = chrono - (d.getTime() - chrono_time_ms_last_update);
|
||||
|
||||
// Let's update chronometer
|
||||
var time_str = '';
|
||||
if (chrono > 0)
|
||||
time_str = milliseconds_to_time_string (chrono);
|
||||
return time_str;
|
||||
}
|
||||
|
||||
var upload_speed_refresh_limiter_last_update = 0;
|
||||
var upload_speed_refresh_limiter_last_value = '';
|
||||
function upload_speed_refresh_limiter(speed_str)
|
||||
{
|
||||
var d = new Date();
|
||||
if (d.getTime() - upload_speed_refresh_limiter_last_update > 1500)
|
||||
{
|
||||
upload_speed_refresh_limiter_last_value = speed_str;
|
||||
upload_speed_refresh_limiter_last_update = d.getTime();
|
||||
}
|
||||
return upload_speed_refresh_limiter_last_value;
|
||||
}
|
||||
|
||||
// document.ready()
|
||||
document.addEventListener('DOMContentLoaded', function(event) {
|
||||
// Search for all datetime fields and convert the time to local timezone
|
||||
convertAllDatetimeFields();
|
||||
});
|
||||
|
||||
// Add copy event listeners
|
||||
function copyLinkToClipboard(link_id) {
|
||||
var focus = document.activeElement;
|
||||
var e = document.getElementById(link_id);
|
||||
|
||||
var tmp = document.createElement("textarea");
|
||||
document.body.appendChild(tmp);
|
||||
tmp.textContent = e.href;
|
||||
tmp.focus();
|
||||
tmp.setSelectionRange(0, tmp.value.length);
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(tmp);
|
||||
|
||||
focus.focus();
|
||||
}
|
||||
|
||||
function addCopyListener(button_id, link_id) {
|
||||
if(document.getElementById(button_id)){
|
||||
document.getElementById(button_id)
|
||||
.addEventListener("click", function() {
|
||||
copyLinkToClipboard(link_id);});
|
||||
}
|
||||
}
|
||||
// @license-end
|
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Kaz addon (see https://git.kaz.bzh/KAZ/depollueur for information)
|
||||
* only upload file for restricted acces purpose
|
||||
* version : 2.22 (2024-12-09)
|
||||
*/
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
define ('JIRAFEAU_ROOT', dirname (__FILE__) . '/');
|
||||
|
||||
require (JIRAFEAU_ROOT . 'lib/settings.php');
|
||||
require (JIRAFEAU_ROOT . 'lib/functions.php');
|
||||
require (JIRAFEAU_ROOT . 'lib/lang.php');
|
||||
|
||||
// ========================================
|
||||
function period2seconds ($periodName) {
|
||||
if (!$periodName)
|
||||
return JIRAFEAU_MONTH;
|
||||
switch ($periodName) {
|
||||
case 'minute':
|
||||
return JIRAFEAU_MINUTE;
|
||||
break;
|
||||
case 'hour':
|
||||
return JIRAFEAU_HOUR;
|
||||
break;
|
||||
case 'day':
|
||||
return JIRAFEAU_DAY;
|
||||
break;
|
||||
case 'week':
|
||||
return JIRAFEAU_WEEK;
|
||||
break;
|
||||
case 'month':
|
||||
return JIRAFEAU_MONTH;
|
||||
break;
|
||||
case 'quarter':
|
||||
return JIRAFEAU_QUARTER;
|
||||
break;
|
||||
case 'semester':
|
||||
return JIRAFEAU_SEMESTER;
|
||||
break;
|
||||
case 'year':
|
||||
return JIRAFEAU_YEAR;
|
||||
break;
|
||||
default:
|
||||
returnError (t ('ERR_OCC') . ' (periodName)');
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
function returnError ($msg) {
|
||||
require (JIRAFEAU_ROOT.'lib/template/header.php');
|
||||
echo '<div class="error"><p>' . $msg . '</p></div>';
|
||||
require (JIRAFEAU_ROOT.'lib/template/footer.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (! isset ($_FILES ['file'])) {
|
||||
// XXX t ("OnlyUpload")
|
||||
returnError ("Only upload file");
|
||||
}
|
||||
|
||||
// ========================================
|
||||
$maxtime = time ()+period2seconds ($_REQUEST ['time']);
|
||||
$key = isset ($_REQUEST ['key']) ? $_REQUEST ['key'] : '';
|
||||
$ip = $_SERVER ['HTTP_X_REAL_IP']; // XXX
|
||||
$res = jirafeau_upload (
|
||||
$_FILES['file'],
|
||||
isset ($_POST ['one_time_download']),
|
||||
$key,
|
||||
$maxtime,
|
||||
$ip,
|
||||
$cfg['enable_crypt'],
|
||||
$cfg['link_name_length'],
|
||||
$cfg['file_hash']
|
||||
);
|
||||
if (! count ($res ['error']) || $res['error']['has_error'])
|
||||
$content = 'Error 6 ' . $res['error']['why'];
|
||||
else
|
||||
$content = $res ['link'].NL.$res ['delete_link'].NL;
|
||||
header ('HTTP/1.0 200 OK');
|
||||
header ('Content-Length: ' . strlen ($content));
|
||||
header ('Content-Type: text/plain');
|
||||
echo $content;
|
||||
exit;
|
||||
|
||||
// ========================================
|
@ -1,519 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Jirafeau, your web file repository
|
||||
* Copyright (C) 2015 Jerome Jutteau <jerome@jutteau.fr>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file offer a kind of API for jirafeau. */
|
||||
|
||||
define('JIRAFEAU_ROOT', dirname(__FILE__) . '/');
|
||||
|
||||
require(JIRAFEAU_ROOT . 'lib/settings.php');
|
||||
require(JIRAFEAU_ROOT . 'lib/functions.php');
|
||||
require(JIRAFEAU_ROOT . 'lib/lang.php');
|
||||
|
||||
global $script_langages;
|
||||
$script_langages = array('bash' => 'Bash');
|
||||
|
||||
/* Operations may take a long time.
|
||||
* Be sure PHP's safe mode is off.
|
||||
*/
|
||||
@set_time_limit(0);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "GET" && count($_GET) == 0) {
|
||||
require(JIRAFEAU_ROOT . 'lib/template/header.php');
|
||||
check_errors($cfg);
|
||||
if (has_error()) {
|
||||
show_errors();
|
||||
require(JIRAFEAU_ROOT . 'lib/template/footer.php');
|
||||
exit;
|
||||
} ?>
|
||||
<div class="info">
|
||||
<h2>Scripting interface</h2>
|
||||
<p>This interface permits to script your uploads and downloads.</p>
|
||||
<p>See <a href="https://gitlab.com/mojo42/Jirafeau/blob/master/script.php">source code</a> of this interface to get available calls :)</p>
|
||||
<p>You may download a preconfigured <a href="script.php?lang=bash">Bash Script</a> to easily send to and get files from the API via command line.</p>
|
||||
</div>
|
||||
<br />
|
||||
<?php
|
||||
require(JIRAFEAU_ROOT . 'lib/template/footer.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Lets use interface now. */
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
|
||||
check_errors($cfg);
|
||||
if (has_error()) {
|
||||
echo 'Error 1';
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Upload file */
|
||||
if (isset($_FILES['file']) && is_writable(VAR_FILES)
|
||||
&& is_writable(VAR_LINKS)) {
|
||||
if (isset($_POST['upload_password'])) {
|
||||
if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), $_POST['upload_password'])) {
|
||||
echo 'Error 3: Invalid password';
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), null)) {
|
||||
echo 'Error 2: No password nor allowed IP';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
$key = '';
|
||||
if (isset($_POST['key'])) {
|
||||
$key = $_POST['key'];
|
||||
}
|
||||
|
||||
$time = time();
|
||||
if (!isset($_POST['time']) || !$cfg['availabilities'][$_POST['time']]) {
|
||||
echo 'Error 4: The parameter time is invalid.';
|
||||
exit;
|
||||
} else {
|
||||
switch ($_POST['time']) {
|
||||
case 'minute':
|
||||
$time += JIRAFEAU_MINUTE;
|
||||
break;
|
||||
case 'hour':
|
||||
$time += JIRAFEAU_HOUR;
|
||||
break;
|
||||
case 'day':
|
||||
$time += JIRAFEAU_DAY;
|
||||
break;
|
||||
case 'week':
|
||||
$time += JIRAFEAU_WEEK;
|
||||
break;
|
||||
case 'month':
|
||||
$time += JIRAFEAU_MONTH;
|
||||
break;
|
||||
case 'quarter':
|
||||
$time += JIRAFEAU_QUARTER;
|
||||
break;
|
||||
case 'semester':
|
||||
$time += JIRAFEAU_SEMESTER;
|
||||
break;
|
||||
case 'year':
|
||||
$time += JIRAFEAU_YEAR;
|
||||
break;
|
||||
default:
|
||||
$time = JIRAFEAU_INFINITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check file size
|
||||
if ($cfg['maximal_upload_size'] > 0 &&
|
||||
$_FILES['file']['size'] > $cfg['maximal_upload_size'] * 1024 * 1024) {
|
||||
echo 'Error 5: Your file exceeds the maximum authorized file size.';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if one time download is enabled
|
||||
if (!$cfg['one_time_download'] && isset($_POST['one_time_download'])) {
|
||||
echo 'Error 26: One time download is disabled.';
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($cfg['store_uploader_ip']) {
|
||||
$ip = get_ip_address($cfg);
|
||||
} else {
|
||||
$ip = "";
|
||||
}
|
||||
|
||||
$res = jirafeau_upload(
|
||||
$_FILES['file'],
|
||||
isset($_POST['one_time_download']),
|
||||
$key,
|
||||
$time,
|
||||
$ip,
|
||||
$cfg['enable_crypt'],
|
||||
$cfg['link_name_length'],
|
||||
$cfg['file_hash']
|
||||
);
|
||||
|
||||
if (empty($res) || $res['error']['has_error']) {
|
||||
echo 'Error 6 ' . $res['error']['why'];
|
||||
exit;
|
||||
}
|
||||
/* Print direct link. */
|
||||
echo $res['link'];
|
||||
/* Print delete link. */
|
||||
echo NL;
|
||||
echo $res['delete_link'];
|
||||
/* Print decrypt key. */
|
||||
echo NL;
|
||||
echo urlencode($res['crypt_key']);
|
||||
} elseif (isset($_GET['h'])) {
|
||||
$link_name = $_GET['h'];
|
||||
$key = '';
|
||||
if (isset($_POST['key'])) {
|
||||
$key = $_POST['key'];
|
||||
}
|
||||
$d = '';
|
||||
if (isset($_GET['d'])) {
|
||||
$d = $_GET['d'];
|
||||
}
|
||||
|
||||
if (!preg_match('/[0-9a-zA-Z_-]+$/', $link_name)) {
|
||||
echo 'Error 7';
|
||||
exit;
|
||||
}
|
||||
|
||||
$link = jirafeau_get_link($link_name);
|
||||
if (count($link) == 0) {
|
||||
echo 'Error 8';
|
||||
exit;
|
||||
}
|
||||
if (strlen($d) > 0 && $d == $link['link_code']) {
|
||||
jirafeau_delete_link($link_name);
|
||||
echo "Ok";
|
||||
exit;
|
||||
}
|
||||
if ($link['time'] != JIRAFEAU_INFINITY && time() > $link['time']) {
|
||||
jirafeau_delete_link($link_name);
|
||||
echo 'Error 9';
|
||||
exit;
|
||||
}
|
||||
if (strlen($link['key']) > 0 && md5($key) != $link['key']) {
|
||||
sleep(2);
|
||||
echo 'Error 10';
|
||||
exit;
|
||||
}
|
||||
$p = s2p($link['hash']);
|
||||
if (!file_exists(VAR_FILES . $p . $link['hash'])) {
|
||||
echo 'Error 11';
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Read file. */
|
||||
header('Content-Length: ' . $link['file_size']);
|
||||
header('Content-Type: ' . $link['mime_type']);
|
||||
header('Content-Disposition: attachment; filename="' .
|
||||
$link['file_name'] . '"');
|
||||
|
||||
$r = fopen(VAR_FILES . $p . $link['hash'], 'r');
|
||||
while (!feof($r)) {
|
||||
print fread($r, 1024);
|
||||
}
|
||||
fclose($r);
|
||||
|
||||
if ($link['onetime'] == 'O') {
|
||||
jirafeau_delete_link($link_name);
|
||||
}
|
||||
exit;
|
||||
} elseif (isset($_GET['get_capacity'])) {
|
||||
echo jirafeau_get_max_upload_size_bytes();
|
||||
} elseif (isset($_GET['get_maximal_upload_size'])) {
|
||||
echo $cfg['maximal_upload_size'];
|
||||
} elseif (isset($_GET['get_version'])) {
|
||||
echo JIRAFEAU_VERSION;
|
||||
} elseif (isset($_GET['lang'])) {
|
||||
$l=$_GET['lang'];
|
||||
if ($l == "bash") {
|
||||
?>
|
||||
#!/bin/bash
|
||||
|
||||
# This script has been auto-generated by Jirafeau but you can still edit options below.
|
||||
|
||||
# Config begin
|
||||
proxy='' # Or set JIRAFEAU_PROXY.
|
||||
url='<?php echo $cfg['web_root']; ?>' # Or set JIRAFEAU_URL.
|
||||
time='<?php echo $cfg['availability_default']; ?>' # Or set JIRAFEAU_TIME.
|
||||
one_time='' # Or set JIRAFEAU_ONE_TIME.
|
||||
curl='' # Or set JIRAFEAU_CURL_PATH.
|
||||
upload_password='' # Or set JIRAFEAU_UPLOAD_PASSWD
|
||||
# Config end
|
||||
|
||||
if [ -n "$JIRAFEAU_PROXY" ]; then
|
||||
proxy="$JIRAFEAU_PROXY"
|
||||
fi
|
||||
|
||||
if [ -n "$JIRAFEAU_URL" ]; then
|
||||
url="$JIRAFEAU_URL"
|
||||
fi
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
echo "Please set url in script parameters or export JIRAFEAU_URL"
|
||||
fi
|
||||
|
||||
if [ -n "$JIRAFEAU_TIME" ]; then
|
||||
time="$JIRAFEAU_TIME"
|
||||
fi
|
||||
|
||||
if [ -n "$JIRAFEAU_ONE_TIME" ]; then
|
||||
one_time='1'
|
||||
fi
|
||||
|
||||
if [ -n "$UPLOAD_PASSWD" ]; then
|
||||
upload_password="$JIRAFEAU_UPLOAD_PASSWORD"
|
||||
fi
|
||||
|
||||
if [ -z "$curl" ]; then
|
||||
curl="$JIRAFEAU_CURL_PATH"
|
||||
fi
|
||||
|
||||
if [ -z "$curl" ] && [ -e "/usr/bin/curl" ]; then
|
||||
curl="/usr/bin/curl"
|
||||
fi
|
||||
|
||||
if [ -z "$curl" ] && [ -e "/bin/curl.exe" ]; then
|
||||
curl="/bin/curl.exe"
|
||||
fi
|
||||
|
||||
if [ -z "$curl" ]; then
|
||||
echo "Please set your curl binary path (by editing this script or export JIRAFEAU_CURL_PATH global variable)."
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$2" ]; then
|
||||
echo "Jirafeau Bash Script <?php echo JIRAFEAU_VERSION; ?>"
|
||||
echo "--------------------------"
|
||||
echo "Usage:"
|
||||
echo " $0 OPTIONS"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " $0 send FILE [PASSWORD]"
|
||||
echo " $0 get URL [PASSWORD]"
|
||||
echo " $0 delete URL"
|
||||
echo
|
||||
echo "Global variables to export:"
|
||||
echo " JIRAFEAU_PROXY: Domain and port of proxy server, eg. »proxysever.example.com:3128«"
|
||||
echo " JIRAFEAU_URL : URI to Jirafeau installation with trailing slash, eg. »https://example.com/jirafeau/«"
|
||||
echo " JIRAFEAU_TIME : expiration time, eg. »minute«, »hour«, »day«, »week«, »month«, »quarter«, »semester«, »year« or »none«"
|
||||
echo " JIRAFEAU_ONE_TIME : self-destroy after first download, eg. »1« to enable or »« (empty) to disable"
|
||||
echo " JIRAFEAU_CURL : alternative path to curl binary"
|
||||
echo " JIRAFEAU_UPLOAD_PASSWD : upload password"
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -n "$proxy" ]; then
|
||||
proxy="-x $proxy"
|
||||
fi
|
||||
|
||||
options=''
|
||||
if [ -n "$one_time" ]; then
|
||||
options="$options -F one_time_download=1"
|
||||
fi
|
||||
|
||||
if [ -n "$upload_password" ]; then
|
||||
options="$options -F upload_password=$upload_password"
|
||||
fi
|
||||
|
||||
password=''
|
||||
if [ -n "$3" ]; then
|
||||
password="$3"
|
||||
options="$options -F key=$password"
|
||||
fi
|
||||
|
||||
apipage='script.php'
|
||||
downloadpage='f.php'
|
||||
|
||||
if [ "$1" == "send" ]; then
|
||||
if [ ! -f "$2" ]; then
|
||||
echo "File \"$2\" does not exists."
|
||||
exit
|
||||
fi
|
||||
|
||||
# Ret result
|
||||
res=$($curl -X POST --http1.0 $proxy $options \
|
||||
-F "time=$time" \
|
||||
-F "file=@$2" \
|
||||
$url$apipage)
|
||||
|
||||
if [[ "$res" == Error* ]]; then
|
||||
echo "Error while uploading."
|
||||
echo $res
|
||||
exit
|
||||
fi
|
||||
|
||||
# Not using head or tail to minimise command dependencies
|
||||
code=$(cnt=0; echo "$res" | while read l; do
|
||||
if [[ "$cnt" == "0" ]]; then
|
||||
echo "$l"
|
||||
fi
|
||||
cnt=$(( cnt + 1 ))
|
||||
done)
|
||||
del_code=$(cnt=0; echo "$res" | while read l; do
|
||||
if [[ "$cnt" == "1" ]]; then
|
||||
echo "$l"
|
||||
fi
|
||||
cnt=$(( cnt + 1 ))
|
||||
done)
|
||||
key_code=$(cnt=0; echo "$res" | while read l; do
|
||||
if [[ "$cnt" == "2" ]]; then
|
||||
echo "$l"
|
||||
fi
|
||||
cnt=$(( cnt + 1 ))
|
||||
done)
|
||||
|
||||
echo
|
||||
echo "Download page:"
|
||||
if [[ $key_code ]]; then
|
||||
echo " ${url}${downloadpage}?h=$code&k=$key_code"
|
||||
else
|
||||
echo " ${url}${downloadpage}?h=$code"
|
||||
fi
|
||||
echo "Direct download:"
|
||||
if [[ $key_code ]]; then
|
||||
echo " ${url}${downloadpage}?h=$code&k=$key_code&d=1"
|
||||
else
|
||||
echo " ${url}${downloadpage}?h=$code&d=1"
|
||||
fi
|
||||
echo "Delete link:"
|
||||
echo " ${url}${downloadpage}?h=$code&d=$del_code"
|
||||
echo
|
||||
echo "Download via API:"
|
||||
if [[ $key_code ]]; then
|
||||
echo " ${0} get ${url}${apipage}?h=$code&k=$key_code [PASSWORD}"
|
||||
else
|
||||
echo " ${0} get ${url}${apipage}?h=$code [PASSWORD}"
|
||||
fi
|
||||
echo "Delete via API:"
|
||||
echo " ${0} delete ${url}${downloadpage}?h=$code&d=$del_code"
|
||||
|
||||
elif [ "$1" == "get" ]; then
|
||||
if [ -z "$password" ]; then
|
||||
$curl $proxy -OJ "$2"
|
||||
else
|
||||
$curl $proxy -OJ -X POST -F key=$password "$2"
|
||||
fi
|
||||
elif [ "$1" == "delete" ]; then
|
||||
$curl $proxy "$2"
|
||||
fi
|
||||
<?php
|
||||
} else {
|
||||
echo 'Error 12';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
/* Initialize an asynchronous upload. */
|
||||
elseif (isset($_GET['init_async'])) {
|
||||
if (isset($_POST['upload_password'])) {
|
||||
if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), $_POST['upload_password'])) {
|
||||
echo 'Error 20: Invalid password';
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), null)) {
|
||||
echo 'Error 19: No password nor allowed IP';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($_POST['filename'])) {
|
||||
echo 'Error 21';
|
||||
exit;
|
||||
}
|
||||
|
||||
$type = '';
|
||||
if (isset($_POST['type'])) {
|
||||
$type = $_POST['type'];
|
||||
}
|
||||
|
||||
$key = '';
|
||||
if (isset($_POST['key'])) {
|
||||
$key = $_POST['key'];
|
||||
}
|
||||
|
||||
// Check if one time download is enabled
|
||||
if (!$cfg['one_time_download'] && isset($_POST['one_time_download'])) {
|
||||
echo 'Error 26: One time download is disabled.';
|
||||
exit;
|
||||
}
|
||||
|
||||
$time = time();
|
||||
if (!isset($_POST['time']) || !$cfg['availabilities'][$_POST['time']]) {
|
||||
echo 'Error 22';
|
||||
exit;
|
||||
} else {
|
||||
switch ($_POST['time']) {
|
||||
case 'minute':
|
||||
$time += JIRAFEAU_MINUTE;
|
||||
break;
|
||||
case 'hour':
|
||||
$time += JIRAFEAU_HOUR;
|
||||
break;
|
||||
case 'day':
|
||||
$time += JIRAFEAU_DAY;
|
||||
break;
|
||||
case 'week':
|
||||
$time += JIRAFEAU_WEEK;
|
||||
break;
|
||||
case 'month':
|
||||
$time += JIRAFEAU_MONTH;
|
||||
break;
|
||||
case 'quarter':
|
||||
$time += JIRAFEAU_QUARTER;
|
||||
break;
|
||||
case 'semester':
|
||||
$time += JIRAFEAU_SEMESTER;
|
||||
break;
|
||||
case 'year':
|
||||
$time += JIRAFEAU_YEAR;
|
||||
break;
|
||||
default:
|
||||
$time = JIRAFEAU_INFINITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($cfg['store_uploader_ip']) {
|
||||
$ip = get_ip_address($cfg);
|
||||
} else {
|
||||
$ip = "";
|
||||
}
|
||||
|
||||
echo jirafeau_async_init(
|
||||
$_POST['filename'],
|
||||
$type,
|
||||
isset($_POST['one_time_download']),
|
||||
$key,
|
||||
$time,
|
||||
$ip
|
||||
);
|
||||
}
|
||||
/* Continue an asynchronous upload. */
|
||||
elseif (isset($_GET['push_async'])) {
|
||||
if ((!isset($_POST['ref']))
|
||||
|| (!isset($_FILES['data']))
|
||||
|| (!isset($_POST['code']))) {
|
||||
echo 'Error 23';
|
||||
} else {
|
||||
echo jirafeau_async_push(
|
||||
$_POST['ref'],
|
||||
$_FILES['data'],
|
||||
$_POST['code'],
|
||||
$cfg['maximal_upload_size']
|
||||
);
|
||||
}
|
||||
}
|
||||
/* Finalize an asynchronous upload. */
|
||||
elseif (isset($_GET['end_async'])) {
|
||||
if (!isset($_POST['ref'])
|
||||
|| !isset($_POST['code'])) {
|
||||
echo 'Error 24';
|
||||
} else {
|
||||
echo jirafeau_async_end($_POST['ref'], $_POST['code'], $cfg['enable_crypt'], $cfg['link_name_length'], $cfg['file_hash']);
|
||||
}
|
||||
} else {
|
||||
echo 'Error 25';
|
||||
}
|
||||
exit;
|
||||
?>
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Jirafeau, your web file repository
|
||||
* Copyright (C) 2008 Julien "axolotl" BERNARD <axolotl@magieeternelle.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
global $cfg;
|
||||
|
||||
// Read config files
|
||||
require(JIRAFEAU_ROOT . 'lib/config.original.php');
|
||||
if (file_exists(JIRAFEAU_ROOT . 'lib/config.local.php')) {
|
||||
// read local copy and merge with original values
|
||||
$cfgOriginal = $cfg;
|
||||
require(JIRAFEAU_ROOT . 'lib/config.local.php');
|
||||
$cfg = array_merge($cfgOriginal, $cfg);
|
||||
unset($cfgOriginal);
|
||||
}
|
||||
|
||||
// Setup debug mode
|
||||
if ($cfg['debug'] === true) {
|
||||
@error_reporting(E_ALL);
|
||||
} else {
|
||||
@error_reporting(0);
|
||||
}
|
||||
|
||||
|
||||
// Set constants
|
||||
|
||||
/* Jirafeau package */
|
||||
define('JIRAFEAU_PACKAGE', 'Jirafeau');
|
||||
define('JIRAFEAU_VERSION', '4.3.0');
|
||||
|
||||
/* Directories. */
|
||||
define('VAR_FILES', $cfg['var_root'] . 'files/');
|
||||
define('VAR_LINKS', $cfg['var_root'] . 'links/');
|
||||
define('VAR_ASYNC', $cfg['var_root'] . 'async/');
|
||||
|
||||
// helping variable to build absolute link to
|
||||
// root of the domain without handling the URL scheme
|
||||
$absPrefix = parse_url($cfg['web_root'], PHP_URL_PATH);
|
||||
if (true === empty($absPrefix)) {
|
||||
// fallback if installation isnt done yet: relative links to same level on the current page
|
||||
$absPrefix = './';
|
||||
}
|
||||
define('JIRAFEAU_ABSPREFIX', $absPrefix);
|
||||
|
||||
/* Useful constants. */
|
||||
if (!defined('NL')) {
|
||||
define('NL', "\n");
|
||||
}
|
||||
if (!defined('QUOTE')) {
|
||||
define('QUOTE', "'");
|
||||
}
|
||||
|
||||
define('JIRAFEAU_INFINITY', -1);
|
||||
define('JIRAFEAU_MINUTE', 60); // 60
|
||||
define('JIRAFEAU_HOUR', 3600); // JIRAFEAU_MINUTE * 60
|
||||
define('JIRAFEAU_DAY', 86400); // JIRAFEAU_HOUR * 24
|
||||
define('JIRAFEAU_WEEK', 604800); // JIRAFEAU_DAY * 7
|
||||
define('JIRAFEAU_MONTH', 2592000); // JIRAFEAU_DAY * 30
|
||||
define('JIRAFEAU_QUARTER', 7776000); // JIRAFEAU_DAY * 90
|
||||
define('JIRAFEAU_SEMESTER', 110678400); // JIRAFEAU_DAY * 183
|
||||
define('JIRAFEAU_YEAR', 31536000); // JIRAFEAU_DAY * 365
|
||||
|
||||
// set UTC as default timezone for all date/time functions
|
||||
date_default_timezone_set('UTC');
|
121
src/Jirafeau/t.php
Normal file
121
src/Jirafeau/t.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
define ('JIRAFEAU_ROOT', dirname (__FILE__) . '/');
|
||||
|
||||
require (JIRAFEAU_ROOT . 'lib/settings.php');
|
||||
require (JIRAFEAU_ROOT . 'lib/functions.php');
|
||||
require (JIRAFEAU_ROOT . 'lib/lang.php');
|
||||
|
||||
@set_time_limit (0);
|
||||
/* Remove errors. */
|
||||
@error_reporting (0);
|
||||
|
||||
if (isset ($_REQUEST ['l']) && !empty ($_REQUEST ['l']))
|
||||
$linksPass = explode ("/", $_REQUEST ["l"]);
|
||||
else if (isset ($_REQUEST ['h']) && !empty ($_REQUEST ['h']))
|
||||
$linksPass = $_REQUEST ["h"];
|
||||
else
|
||||
die ("no links");
|
||||
|
||||
if (!is_array ($linksPass))
|
||||
die ("no list is given: ".$h);
|
||||
|
||||
$notFoundCount=0;
|
||||
$map = [];
|
||||
// First pass: check
|
||||
foreach ($linksPass as $line) {
|
||||
if (strpos ($line, '~') !== false)
|
||||
$couple = explode ("~", $line, 2);
|
||||
else
|
||||
$couple = explode ("/", $line, 2);
|
||||
if (count ($couple) == 0)
|
||||
continue;
|
||||
$link_name = $couple [0];
|
||||
if (!$link_name)
|
||||
continue;
|
||||
$crypt_key = count ($couple) == 2 ? $couple [1] : "";
|
||||
if (!preg_match ('/[0-9a-zA-Z_-]+$/', $link_name))
|
||||
die ("bad link format : ".$link_name);
|
||||
$link = jirafeau_get_link ($link_name);
|
||||
if (count ($link) == 0) {
|
||||
++$notFoundCount;
|
||||
continue;
|
||||
}
|
||||
$key = $link['key'];
|
||||
if ($key) {
|
||||
preg_match ( '/[0-9a-zA-Z_-]+/', $link['key'], $matches);
|
||||
$key = $matches[1];
|
||||
}
|
||||
if ($key && (empty ($crypt_key) || $key != $crypt_key))
|
||||
die ("bad key for ".$link);
|
||||
$map [$link_name] = $crypt_key;
|
||||
}
|
||||
|
||||
// second pass: send
|
||||
if (isset ($_REQUEST ['n']) && !empty ($_REQUEST ['n']))
|
||||
$dirname=$_REQUEST ['n'];
|
||||
else
|
||||
$dirname="kaz-".date ("Ymd-His");
|
||||
$tmpFileName = tempnam (sys_get_temp_dir (), $dirname."-");
|
||||
$zip = new ZipArchive;
|
||||
if (!$zip)
|
||||
die ("can't create tmp");
|
||||
if ($zip->open ($tmpFileName.".zip", ZipArchive::CREATE) !== TRUE)
|
||||
die ("can't create tmp");
|
||||
|
||||
if ($notFoundCount) {
|
||||
$zip->addFromString ($dirname."-Avertissement.txt", $notFoundCount. ($notFoundCount ? " fichier est expiré." : " fichiers sont expirés."));
|
||||
}
|
||||
$single_name=[];
|
||||
foreach ($map as $link_name => $crypt_key) {
|
||||
$link = jirafeau_get_link ($link_name);
|
||||
$p = s2p ($link ['hash']);
|
||||
|
||||
$src_name = $dst_name = $link['file_name'];
|
||||
if (in_array ($src_name, $single_name))
|
||||
for ($i = 0; $i < 10000; ++$i) {
|
||||
$dst_name = sprintf ("%s-%2d", $src_name, $i);
|
||||
if (!in_array ($dst_name, $single_name))
|
||||
break;
|
||||
}
|
||||
$single_name[]=$dst_name;
|
||||
|
||||
// send
|
||||
if ($link['crypted']) {
|
||||
$m = mcrypt_module_open ('rijndael-256', '', 'ofb', '');
|
||||
$md5_key = md5 ($crypt_key);
|
||||
$iv = jirafeau_crypt_create_iv ($md5_key, mcrypt_enc_get_iv_size ($m));
|
||||
mcrypt_generic_init ($m, $md5_key, $iv);
|
||||
$r = fopen (VAR_FILES . $p . $link['hash'], 'r');
|
||||
$content = "";
|
||||
while (!feof ($r)) {
|
||||
$dec = mdecrypt_generic ($m, fread ($r, 1024));
|
||||
$content .= $dec;
|
||||
ob_flush ();
|
||||
}
|
||||
fclose ($r);
|
||||
$zip->addFromString ($dirname."/".$dst_name, $content);
|
||||
|
||||
mcrypt_generic_deinit ($m);
|
||||
mcrypt_module_close ($m);
|
||||
continue;
|
||||
}
|
||||
$zip->addFile (VAR_FILES . $p . $link['hash'], $dirname."/".$dst_name);
|
||||
}
|
||||
$zip->close ();
|
||||
|
||||
|
||||
if (!is_file ($tmpFileName.".zip"))
|
||||
die ("can't retreive tmp");
|
||||
|
||||
header ("HTTP/1.0 200 OK");
|
||||
header ("Content-Type: application/zip");
|
||||
header ('Content-Disposition: filename="'.$dirname.'.zip"');
|
||||
$r = fopen($tmpFileName.".zip", 'r');
|
||||
while (!feof ($r)) {
|
||||
print fread ($r, 1024);
|
||||
ob_flush ();
|
||||
}
|
||||
fclose ($r);
|
||||
|
||||
unlink ($tmpFileName.".zip");
|
||||
unlink ($tmpFileName);
|
@ -1,78 +0,0 @@
|
||||
#!/bin/bash
|
||||
##########################################################################
|
||||
# Copyright KAZ 2021 #
|
||||
# #
|
||||
# contact (at) kaz.bzh #
|
||||
# #
|
||||
# This software is a filter to shrink email by attachment extraction. #
|
||||
# #
|
||||
# This software is governed by the CeCILL-B license under French law and #
|
||||
# abiding by the rules of distribution of free software. You can use, #
|
||||
# modify and/or redistribute the software under the terms of the #
|
||||
# CeCILL-B license as circulated by CEA, CNRS and INRIA at the following #
|
||||
# URL "http://www.cecill.info". #
|
||||
# #
|
||||
# As a counterpart to the access to the source code and rights to copy, #
|
||||
# modify and redistribute granted by the license, users are provided #
|
||||
# only with a limited warranty and the software's author, the holder of #
|
||||
# the economic rights, and the successive licensors have only limited #
|
||||
# liability. #
|
||||
# #
|
||||
# In this respect, the user's attention is drawn to the risks associated #
|
||||
# with loading, using, modifying and/or developing or reproducing the #
|
||||
# software by the user in light of its specific status of free software, #
|
||||
# that may mean that it is complicated to manipulate, and that also #
|
||||
# therefore means that it is reserved for developers and experienced #
|
||||
# professionals having in-depth computer knowledge. Users are therefore #
|
||||
# encouraged to load and test the software's suitability as regards #
|
||||
# their requirements in conditions enabling the security of their #
|
||||
# systems and/or data to be ensured and, more generally, to use and #
|
||||
# operate it in the same conditions as regards security. #
|
||||
# #
|
||||
# The fact that you are presently reading this means that you have had #
|
||||
# knowledge of the CeCILL-B license and that you accept its terms. #
|
||||
##########################################################################
|
||||
|
||||
PRG=$(basename $0)
|
||||
|
||||
usage () {
|
||||
echo "Usage: ${PRG} logDir"
|
||||
exit 1
|
||||
}
|
||||
|
||||
BOLD='\e[1m'
|
||||
RED='\e[0;31m'
|
||||
GREEN='\e[0;32m'
|
||||
YELLOW='\e[0;33m'
|
||||
BLUE='\e[0;34m'
|
||||
MAGENTA='\e[0;35m'
|
||||
CYAN='\e[0;36m'
|
||||
NC='\e[0m' # No Color
|
||||
NL='
|
||||
'
|
||||
[ "$#" -eq 1 ] || usage
|
||||
logDir=$(realpath "$1")
|
||||
|
||||
########################################
|
||||
# recherche des binaires
|
||||
cd $(dirname $0)
|
||||
eMailShrinker="$(realpath "./eMailShrinker")"
|
||||
[ -x "${eMailShrinker}" ] || eMailShrinker="$(realpath "../../build/out/eMailShrinker")"
|
||||
[ -x "${eMailShrinker}" ] || ( echo "${RED}eMailShrinker not found${NC}" ; exit)
|
||||
|
||||
|
||||
cd "${logDir}"
|
||||
for i in in.*.orig;
|
||||
do
|
||||
clear
|
||||
echo -e " ${GREEN}${BOLD}${i//.orig}${NC}\n"
|
||||
"${eMailShrinker}" -l ${i}
|
||||
echo -e "\n ####################\n"
|
||||
"${eMailShrinker}" -l ${i//.orig}.altered
|
||||
echo -en "\n(q = quit / y = rm / default = continue)? "
|
||||
read rep
|
||||
case "${rep}" in
|
||||
"q" ) break;;
|
||||
"y") rm ${i} ${i//.orig}.altered
|
||||
esac
|
||||
done
|
@ -1,99 +0,0 @@
|
||||
#!/bin/bash
|
||||
##########################################################################
|
||||
# Copyright KAZ 2021 #
|
||||
# #
|
||||
# contact (at) kaz.bzh #
|
||||
# #
|
||||
# This software is a filter to shrink email by attachment extraction. #
|
||||
# #
|
||||
# This software is governed by the CeCILL-B license under French law and #
|
||||
# abiding by the rules of distribution of free software. You can use, #
|
||||
# modify and/or redistribute the software under the terms of the #
|
||||
# CeCILL-B license as circulated by CEA, CNRS and INRIA at the following #
|
||||
# URL "http://www.cecill.info". #
|
||||
# #
|
||||
# As a counterpart to the access to the source code and rights to copy, #
|
||||
# modify and redistribute granted by the license, users are provided #
|
||||
# only with a limited warranty and the software's author, the holder of #
|
||||
# the economic rights, and the successive licensors have only limited #
|
||||
# liability. #
|
||||
# #
|
||||
# In this respect, the user's attention is drawn to the risks associated #
|
||||
# with loading, using, modifying and/or developing or reproducing the #
|
||||
# software by the user in light of its specific status of free software, #
|
||||
# that may mean that it is complicated to manipulate, and that also #
|
||||
# therefore means that it is reserved for developers and experienced #
|
||||
# professionals having in-depth computer knowledge. Users are therefore #
|
||||
# encouraged to load and test the software's suitability as regards #
|
||||
# their requirements in conditions enabling the security of their #
|
||||
# systems and/or data to be ensured and, more generally, to use and #
|
||||
# operate it in the same conditions as regards security. #
|
||||
# #
|
||||
# The fact that you are presently reading this means that you have had #
|
||||
# knowledge of the CeCILL-B license and that you accept its terms. #
|
||||
##########################################################################
|
||||
|
||||
PRG=$(basename $0)
|
||||
FILTER_TEST="$(realpath "$(dirname $0)/filterTest.sh")"
|
||||
|
||||
ATTACH_MODE="FOOTER"
|
||||
|
||||
usage () {
|
||||
echo "Usage: ${PRG} {NONE|FOOTER|ATTACHMENT|BOTH} mbox..."
|
||||
exit 1
|
||||
}
|
||||
|
||||
########################################
|
||||
BOLD='\e[1m'
|
||||
RED='\e[0;31m'
|
||||
GREEN='\e[0;32m'
|
||||
YELLOW='\e[0;33m'
|
||||
BLUE='\e[0;34m'
|
||||
MAGENTA='\e[0;35m'
|
||||
CYAN='\e[0;36m'
|
||||
GREY='\e[0;90m'
|
||||
BG_BLACK='\e[0;40m'
|
||||
BG_RED='\e[0;41m'
|
||||
BG_GREEN='\e[0;42m'
|
||||
BG_YELLOW='\e[0;43m'
|
||||
BG_BLUE='\e[0;44m'
|
||||
BG_MAGENTA='\e[0;45m'
|
||||
CYAN='\e[0;36m'
|
||||
NC='\e[0m' # No Color
|
||||
NL='
|
||||
'
|
||||
|
||||
########################################
|
||||
[ "$#" -lt 2 ] && usage
|
||||
|
||||
ATTACH_MODE="$1"; shift
|
||||
|
||||
case "${ATTACH_MODE}" in
|
||||
""|NONE|FOOTER|ATTACHMENT|BOTH);;
|
||||
*) usage;;
|
||||
esac
|
||||
|
||||
|
||||
start=0
|
||||
loop=true
|
||||
while [ ! -z "${loop}" ]; do
|
||||
loop=""
|
||||
count=0
|
||||
for mbox in $*; do
|
||||
clear
|
||||
((count=count+1))
|
||||
(( count < start )) && continue
|
||||
echo -e " ${GREY}${count}/$# ${GREEN}${BOLD}${mbox}${NC}\n"
|
||||
"${FILTER_TEST}" -s -m "${ATTACH_MODE}" "${mbox}"
|
||||
echo -en "\n(q = quit / [0-9]* = goto / default = continue)? "
|
||||
read rep
|
||||
case "${rep}" in
|
||||
"q" ) break;;
|
||||
[0-9]* )
|
||||
start="${rep}"
|
||||
(( count < start )) && continue
|
||||
loop=true
|
||||
break;;
|
||||
esac
|
||||
done
|
||||
done
|
226
src/bash/filter.sh
Executable file → Normal file
226
src/bash/filter.sh
Executable file → Normal file
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
##########################################################################
|
||||
# Copyright KAZ 2021 #
|
||||
# #
|
||||
@ -32,170 +32,93 @@
|
||||
# The fact that you are presently reading this means that you have had #
|
||||
# knowledge of the CeCILL-B license and that you accept its terms. #
|
||||
##########################################################################
|
||||
# Kaz addon (see https://git.kaz.bzh/KAZ/depollueur for information)
|
||||
# version : 2.22 (2024-12-09)
|
||||
|
||||
##########################################################################
|
||||
# - installer l'utilitaire apg pour génération de mot de passes
|
||||
# - installer l'utilitaire dos2unix
|
||||
# - installer l' utilitaire apg pour génération de mot de passes
|
||||
# - le contenu de INSPECT_DIR doit être accessible en écriture pour le
|
||||
# proriétaire du script
|
||||
# - shrinkEMail doit être accessible en execution pour le proriétaire
|
||||
# - comme le programme n'a pas de privigèle, il faut que root fasse avant :
|
||||
# mkdir -p "${DIR_LOG}/pb/" ; chmod a+rwx "${DIR_LOG}/pb/"
|
||||
# - shrinkEMail et jirafeau.sh doivent être accessible en execution pour
|
||||
# le roriétaire du script
|
||||
##########################################################################
|
||||
|
||||
DEFAULT_MODE="both"
|
||||
DEFAULT_PERIOD="month"
|
||||
DEFAULT_TRACK=""
|
||||
|
||||
cd "$(dirname $0)"
|
||||
DOMAINEDEPOT="$(cat config/domainedepot)"
|
||||
cd $(dirname $0)
|
||||
DOMAINNAME=$(cat domainname)
|
||||
# Exit codes from <sysexits.h>
|
||||
EX_TEMPFAIL=75
|
||||
EX_UNAVAILABLE=69
|
||||
EX_TOO_LARGE=552
|
||||
INSPECT_DIR=/var/spool/filter
|
||||
DIR_LOG=/var/log/mail
|
||||
FIC_LOG="${DIR_LOG}/filter.log"
|
||||
TMP_LOG="$(mktemp)"
|
||||
FIC_LOG=${DIR_LOG}/filter.log
|
||||
SENDMAIL="/usr/sbin/sendmail -G -i"
|
||||
MAILS=/tmp/FILTER
|
||||
MAX_KEEP_IN_MAIL=5ki
|
||||
MAX_UPLOAD_SIZE=1Gi
|
||||
SHRINK_CMD=/home/filter/eMailShrinker
|
||||
JIRAFEAU_URL="https://depot.${DOMAINEDEPOT:-"kaz.bzh"}"
|
||||
JIRAFEAU_CMD=/home/filter/jirafeauAPI
|
||||
JIRAFEAU_URL=https://depot.${DOMAINNAME:-"kaz.bzh"}
|
||||
JIRAFEAU_LOCAL=http://depot
|
||||
JIRAFEAU_TIME=month
|
||||
MD5_CMD=/usr/bin/md5sum
|
||||
DISCLAMER_CMD=altermime
|
||||
MAX_FINAL_SIZE=2097152 # 2Mi
|
||||
MAX_FINAL_SIZE=307200 # 300ki
|
||||
ARCHIVE_TITLE="archive_content"
|
||||
ARCHIVE_MIME="text/kaz_email_archive"
|
||||
|
||||
FILE_SKIP_DOMAINS="config/file_domaines_non_depollues.txt"
|
||||
#on enlève les commentaires et les lignes vides
|
||||
SKIP_DOMAINS="$(sed 's:#.*$::g' 's/[[:blank:]]//g' "${FILE_SKIP_DOMAINS}" 2>/dev/null)"
|
||||
|
||||
KEEP_FAILED=true
|
||||
DEBUG=true
|
||||
DEBUG=
|
||||
|
||||
#################### FONCTIONS ############################################
|
||||
BOLD='\e[1m'
|
||||
RED='\e[0;31m'
|
||||
GREEN='\e[0;32m'
|
||||
YELLOW='\e[0;33m'
|
||||
BLUE='\e[0;34m'
|
||||
MAGENTA='\e[0;35m'
|
||||
CYAN='\e[0;36m'
|
||||
NC='\e[0m' # No Color
|
||||
BOLD='[1m'
|
||||
RED='[0;31m'
|
||||
GREEN='[0;32m'
|
||||
YELLOW='[0;33m'
|
||||
BLUE='[0;34m'
|
||||
MAGENTA='[0;35m'
|
||||
CYAN='[0;36m'
|
||||
NC='[0m' # No Color
|
||||
NL='
|
||||
'
|
||||
|
||||
#--------------------- Fichier de LOG -------------------
|
||||
LOG_FIC () {
|
||||
echo -e "${BLUE}$(date +%d-%m-%Y-%H-%M-%S)${NC} : $*" >> "${TMP_LOG}"
|
||||
echo "${BLUE}$(date +%d-%m-%Y-%H-%M-%S)${NC} : $*" >> "${FIC_LOG}"
|
||||
}
|
||||
|
||||
quitFilter () {
|
||||
LOG_FIC "${GREEN}######################################## filter stop${NC}"
|
||||
cat "${TMP_LOG}" >> "${FIC_LOG}"
|
||||
rm -f "${TMP_LOG}"
|
||||
exit $1
|
||||
}
|
||||
|
||||
keepFailed () {
|
||||
[ -z "${KEEP_FAILED}" ] && return
|
||||
mkdir -p "${DIR_LOG}/pb/"
|
||||
cp "$1" "${DIR_LOG}/pb/"
|
||||
}
|
||||
|
||||
########################################
|
||||
# curl Jirafeau
|
||||
curlJirafeauUpdate () {
|
||||
# $1: periode
|
||||
# $2: jirafeauItemRef
|
||||
LOG_FIC " - ${CYAN}curl -X POST -d \"u=$1\" -d \"h=$2\" \"${JIRAFEAU_LOCAL}/a.php}\""
|
||||
curl -X POST -d "u=$1" -d "h=$2" "${JIRAFEAU_LOCAL}/a.php"
|
||||
}
|
||||
|
||||
curlJirafeauSend () {
|
||||
# $1: periode
|
||||
# $2: filename
|
||||
# $3: content-type
|
||||
# $4: name
|
||||
# $5: password
|
||||
|
||||
type="type=$3;"
|
||||
[ -z "$3" -o "$3" = "/" ] && type=""
|
||||
LOG_FIC " - curl -X POST -F \"time=$1\" -F \"key=$5\" -F \"file=@$2;${type}filename=\\\"$4\\\"\" \"${JIRAFEAU_LOCAL}/s.php\""
|
||||
for num in {1..2}; do
|
||||
OUTPUT=$(curl -X POST -F "time=$1" -F "key=$5" -F "file=@$2;${type}filename=\"$4\"" "${JIRAFEAU_LOCAL}/s.php")
|
||||
read JIR_TOKEN <<< "${OUTPUT}"
|
||||
case "${JIR_TOKEN}" in
|
||||
"" | no | *Error* | \<* )
|
||||
sleep 30
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
break
|
||||
done
|
||||
echo "${OUTPUT}"
|
||||
}
|
||||
|
||||
# Définir une fonction pour vérifier si le domaine d'un email est dans la liste SKIP_DOMAINS
|
||||
function check_skip_domains() {
|
||||
local SKIP_DOMAINS="$1"
|
||||
local LIST_EMAILS="$2"
|
||||
|
||||
for email in ${LIST_EMAILS}; do
|
||||
# Extraire le domaine de l'email (partie après le "@")
|
||||
local domain="${email##*@}"
|
||||
|
||||
for domain in ${SKIP_DOMAINS}; do
|
||||
# vérification si le domaine est dans la liste des domaines à sauter
|
||||
if [[ " ${email} " =~ "${domain} " ]] ; then
|
||||
echo "yes"
|
||||
return
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Si aucun domaine n'a été trouvé, retourner "no"
|
||||
echo "no"
|
||||
}
|
||||
|
||||
#################### MAIN #################################################
|
||||
echo -e "${NL}${BLUE}$(date +%d-%m-%Y-%H-%M-%S)${NC} : ${GREEN}######################################## filter start (log in ${TMP_LOG})${NC}" >> "${FIC_LOG}"
|
||||
LOG_FIC "${GREEN}######################################## ${TMP_LOG} ${NC}"
|
||||
echo "${NL}" >> "${FIC_LOG}"
|
||||
LOG_FIC "${GREEN}######################################## filter start${NC}"
|
||||
|
||||
if ! mkdir -p "${MAILS}"; then
|
||||
LOG_FIC "${RED}Can't mkdir ${MAILS} ${NC}"
|
||||
quitFilter "${EX_UNAVAILABLE}"
|
||||
fi
|
||||
|
||||
#$@ contient le sender et les destinataires
|
||||
#format "-f sender -- dest1 [...dest(i)] "
|
||||
LIST_EMAILS=$(echo $@)
|
||||
#on nettoie
|
||||
LIST_EMAILS=$(sed 's/-f//g' <<< ${LIST_EMAILS})
|
||||
LIST_EMAILS=$(sed 's/--//g' <<< ${LIST_EMAILS})
|
||||
|
||||
MAIL_SOURCE=$(echo $@ | awk 'BEGIN{FS=" "} {print $2}')
|
||||
DATE_TEMPS=$(date "+%Y-%m-%d-%H:%M:%S")
|
||||
REP_PIECE_JOINTE="${MAILS}/${DATE_TEMPS}_${MAIL_SOURCE}_$$"
|
||||
TRACK=$(curl "${JIRAFEAU_LOCAL}/a.php?r=${MAIL_SOURCE}" 2>/dev/null)
|
||||
PERIOD=$(curl "${JIRAFEAU_LOCAL}/a.php?p=${MAIL_SOURCE}" 2>/dev/null)
|
||||
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
|
||||
|
||||
MODE=$(curl "${JIRAFEAU_LOCAL}/a.php?m=${MAIL_SOURCE}" 2>/dev/null )
|
||||
[[ "${MODE}" =~ ^(none|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|semester)$ ]] || PERIOD="${DEFAULT_PERIOD}"
|
||||
|
||||
LOG_FIC "${NL}" \
|
||||
" MAIL_SOURCE : ${YELLOW}${MAIL_SOURCE}${NC}${NL}" \
|
||||
" DATE_TEMPS : ${YELLOW}${DATE_TEMPS=}${NC}${NL}" \
|
||||
" MODE : ${YELLOW}${MODE}${NC}${NL}" \
|
||||
" TRACK : ${YELLOW}${TRACK}${NC}${NL}" \
|
||||
" PERIOD : ${YELLOW}${PERIOD}${NC}${NL}"
|
||||
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"
|
||||
@ -212,60 +135,41 @@ ARCHIVE_CONTENT="${REP_PIECE_JOINTE}/archive-content.txt"
|
||||
JIRAFEAU_ERROR="${REP_PIECE_JOINTE}/jirafeau-error.txt"
|
||||
|
||||
# Clean up when done or when aborting.
|
||||
[ -z "${DEBUG}" ] && trap "cd ${INSPECT_DIR}; 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
|
||||
|
||||
if ! cat > "${INSPECT_DIR}/in.$$"; then
|
||||
if ! cat > "in.$$"; then
|
||||
LOG_FIC "${RED}Cannot save mail to file${NC}"
|
||||
quitFilter "${EX_TEMPFAIL}"
|
||||
fi
|
||||
dos2unix "${INSPECT_DIR}/in.$$" 2> /dev/null
|
||||
|
||||
LOG_FIC "${NL}" \
|
||||
LOG_FIC "\n" \
|
||||
" size: ${YELLOW}$(wc -c < "${INSPECT_DIR}/in.$$")${NC}"
|
||||
[ -z "${DEBUG}" ] || (cp "${INSPECT_DIR}/in.$$" "${DIR_LOG}/pb/in.$$.orig")
|
||||
[ -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}"
|
||||
|
||||
if [ "${MODE}" = "none" ]; then
|
||||
LOG_FIC " - ${GREEN}send without change (MODE=none)${NC}"
|
||||
${SENDMAIL} "$@" < "${INSPECT_DIR}/in.$$"
|
||||
quitFilter 0
|
||||
fi
|
||||
|
||||
|
||||
if [ "$(check_skip_domains "${SKIP_DOMAINS}" "${LIST_EMAILS}")" = "yes" ]; then
|
||||
LOG_FIC " - ${GREEN}send without change (skip domain)${NC}"
|
||||
${SENDMAIL} "$@" < "${INSPECT_DIR}/in.$$"
|
||||
quitFilter 0
|
||||
fi
|
||||
|
||||
########################################
|
||||
# Préparation pour le cloud
|
||||
rm -f "${REP_PIECE_JOINTE}/last.txt"
|
||||
|
||||
# Etape de rafraichissement des anciens fichiers inclus
|
||||
echo "time: ${DATE_TEMPS}${NL}id: $(date +%s)" > "${ARCHIVE_CONTENT}"
|
||||
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>> \"${TMP_LOG}\" > \"${OLD_LINKS}\"${NC}"
|
||||
"${SHRINK_CMD}" -u "${INSPECT_DIR}/in.$$" 2>> "${TMP_LOG}" > "${OLD_LINKS}"
|
||||
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
|
||||
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
|
||||
curlJirafeauUpdate "${PERIOD}" "${REMOTE_REF}" 2>&1 >> "${TMP_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}"
|
||||
echo "h=${REMOTE_REF}~${REMOTE_KEY}" > "${REP_PIECE_JOINTE}/last.txt"
|
||||
done
|
||||
LOG_FIC " - archive starts with: ${NL}${YELLOW}$(cat ${ARCHIVE_CONTENT})${NC}"
|
||||
|
||||
# Etape extraction des pieces jointes
|
||||
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>> "${TMP_LOG}" | {
|
||||
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
|
||||
ATTACH_MEDIA="${ATTACH_TMP_NAME}/media"
|
||||
@ -276,11 +180,11 @@ LOG_FIC "${CYAN}${SHRINK_CMD} -s \"${MAX_KEEP_IN_MAIL}\" -d \"${REP_PIECE_JOINTE
|
||||
# XXX error
|
||||
continue
|
||||
fi
|
||||
|
||||
# Etape de televersement des pieces jointes
|
||||
PASSWORD=$(apg -n 1 -m 12 -M cln)
|
||||
PASSWORD=$(apg -n 1 -m 12)
|
||||
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
|
||||
curlJirafeauSend "${PERIOD}" "${ATTACH_MEDIA}" "${ATTACH_CONTENT_TYPE}" "${ATTACH_NAME}" "${PASSWORD}" 2>> "${TMP_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
|
||||
@ -293,23 +197,21 @@ LOG_FIC "${CYAN}${SHRINK_CMD} -s \"${MAX_KEEP_IN_MAIL}\" -d \"${REP_PIECE_JOINTE
|
||||
echo "UPLOAD_FAIL" >> "${JIRAFEAU_ERROR}"
|
||||
;;
|
||||
* )
|
||||
LOG_FIC " - change by link ${YELLOW}${JIRAFEAU_URL}/f.php?d=0&h=${JIR_TOKEN}&k=${PASSWORD_MD5}${NC}"
|
||||
echo "url: ${JIRAFEAU_URL}/f.php?d=0&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}"
|
||||
echo "h=${JIR_TOKEN}~${PASSWORD_MD5}" > "${REP_PIECE_JOINTE}/last.txt"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
done
|
||||
|
||||
# Création de l'archive
|
||||
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 -M cln)
|
||||
PASSWORD=$(apg -n 1 -m 12)
|
||||
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
|
||||
LOG_FIC " - ${MAGENTA}upload archive${NC}"
|
||||
|
||||
curlJirafeauSend "${PERIOD}" "${ARCHIVE_CONTENT}" "${ARCHIVE_MIME}" "${ARCHIVE_TITLE}" "${PASSWORD}" 2>> "${TMP_LOG}" > "${ONE_LINK}"
|
||||
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
|
||||
@ -327,7 +229,6 @@ LOG_FIC "${CYAN}${SHRINK_CMD} -s \"${MAX_KEEP_IN_MAIL}\" -d \"${REP_PIECE_JOINTE
|
||||
* )
|
||||
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}"
|
||||
echo "g=${JIR_TOKEN}~${PASSWORD_MD5}" > "${REP_PIECE_JOINTE}/last.txt"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@ -335,17 +236,11 @@ LOG_FIC "${CYAN}${SHRINK_CMD} -s \"${MAX_KEEP_IN_MAIL}\" -d \"${REP_PIECE_JOINTE
|
||||
LOG_FIC " - no archive (less than 2 attach file)"
|
||||
echo "arch: none"
|
||||
fi
|
||||
if [ -s "${REP_PIECE_JOINTE}/last.txt" ]; then
|
||||
echo "cloud: ${JIRAFEAU_URL}/c.php?$(cat "${REP_PIECE_JOINTE}/last.txt")"
|
||||
else
|
||||
echo "cloud: none"
|
||||
fi
|
||||
|
||||
# Etape de substitution
|
||||
LOG_FIC "${CYAN}${SHRINK_CMD} -m \"${MODE}\" -s \"${MAX_KEEP_IN_MAIL}\" \"${INSPECT_DIR}/in.$$\" \"${INSPECT_DIR}/in.$$.altered\" 2>> \"${TMP_LOG}\"${NC}"
|
||||
} | "${SHRINK_CMD}" -m "${MODE}" -s "${MAX_KEEP_IN_MAIL}" "${INSPECT_DIR}/in.$$" "${INSPECT_DIR}/in.$$.altered" 2>> "${TMP_LOG}"
|
||||
LOG_FIC "${CYAN}${SHRINK_CMD} -s \"${MAX_KEEP_IN_MAIL}\" \"${INSPECT_DIR}/in.$$\" \"${INSPECT_DIR}/in.$$.altered\" 2>> \"${FIC_LOG}\"${NC}"
|
||||
} | "${SHRINK_CMD}" -s "${MAX_KEEP_IN_MAIL}" "${INSPECT_DIR}/in.$$" "${INSPECT_DIR}/in.$$.altered" 2>> "${FIC_LOG}"
|
||||
|
||||
[ -z "${DEBUG}" ] || (cp "${INSPECT_DIR}/in.$$.altered" "${DIR_LOG}/pb/in.$$.altered")
|
||||
[ -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}"
|
||||
@ -356,7 +251,7 @@ fi
|
||||
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
|
||||
if [ ${actualSize} -ge $MAX_FINAL_SIZE ]; then
|
||||
LOG_FIC " - ${RED}too big even after diet ${INSPECT_DIR}/in.$$.altered (${actualSize})${NC}"
|
||||
keepFailed "${INSPECT_DIR}/in.$$"
|
||||
quitFilter "${EX_TOO_LARGE}"
|
||||
@ -366,16 +261,15 @@ if [ "$(wc -l < "${ARCHIVE_CONTENT}")" -ge 3 ]; then
|
||||
else
|
||||
# verification de taille finale
|
||||
actualSize=$(wc -c < "${INSPECT_DIR}/in.$$")
|
||||
if [ "${actualSize}" -ge "${MAX_FINAL_SIZE}" ]; then
|
||||
if [ ${actualSize} -ge $MAX_FINAL_SIZE ]; then
|
||||
LOG_FIC " - ${RED}too big without diet ${INSPECT_DIR}/in.$$ (${actualSize}) ${NC}"
|
||||
keepFailed "${INSPECT_DIR}/in.$$"
|
||||
quitFilter "${EX_TOO_LARGE}"
|
||||
fi
|
||||
LOG_FIC " - ${GREEN}send without attach file${NC}"
|
||||
${SENDMAIL} "$@" < "${INSPECT_DIR}/in.$$"
|
||||
${SENDMAIL} "$@" < "in.$$"
|
||||
fi
|
||||
|
||||
quitFilter 0
|
||||
|
||||
##########################################################################
|
||||
|
||||
|
@ -1,251 +0,0 @@
|
||||
#!/bin/bash
|
||||
##########################################################################
|
||||
# Copyright KAZ 2021 #
|
||||
# #
|
||||
# contact (at) kaz.bzh #
|
||||
# #
|
||||
# This software is a filter to shrink email by attachment extraction. #
|
||||
# #
|
||||
# This software is governed by the CeCILL-B license under French law and #
|
||||
# abiding by the rules of distribution of free software. You can use, #
|
||||
# modify and/or redistribute the software under the terms of the #
|
||||
# CeCILL-B license as circulated by CEA, CNRS and INRIA at the following #
|
||||
# URL "http://www.cecill.info". #
|
||||
# #
|
||||
# As a counterpart to the access to the source code and rights to copy, #
|
||||
# modify and redistribute granted by the license, users are provided #
|
||||
# only with a limited warranty and the software's author, the holder of #
|
||||
# the economic rights, and the successive licensors have only limited #
|
||||
# liability. #
|
||||
# #
|
||||
# In this respect, the user's attention is drawn to the risks associated #
|
||||
# with loading, using, modifying and/or developing or reproducing the #
|
||||
# software by the user in light of its specific status of free software, #
|
||||
# that may mean that it is complicated to manipulate, and that also #
|
||||
# therefore means that it is reserved for developers and experienced #
|
||||
# professionals having in-depth computer knowledge. Users are therefore #
|
||||
# encouraged to load and test the software's suitability as regards #
|
||||
# their requirements in conditions enabling the security of their #
|
||||
# systems and/or data to be ensured and, more generally, to use and #
|
||||
# operate it in the same conditions as regards security. #
|
||||
# #
|
||||
# The fact that you are presently reading this means that you have had #
|
||||
# knowledge of the CeCILL-B license and that you accept its terms. #
|
||||
##########################################################################
|
||||
# Kaz addon (see https://git.kaz.bzh/KAZ/depollueur for information)
|
||||
# version : 2.22 (2024-12-09)
|
||||
|
||||
PRG=$(basename $0)
|
||||
|
||||
ATTACH_MODE="FOOTER"
|
||||
export SIMULATE=""
|
||||
|
||||
BOLD='\e[1m'
|
||||
RED='\e[0;31m'
|
||||
GREEN='\e[0;32m'
|
||||
YELLOW='\e[0;33m'
|
||||
BLUE='\e[0;34m'
|
||||
MAGENTA='\e[0;35m'
|
||||
CYAN='\e[0;36m'
|
||||
NC='\e[0m' # No Color
|
||||
NL='
|
||||
'
|
||||
|
||||
PERIODE="month"
|
||||
MD5_CMD=/usr/bin/md5sum
|
||||
########################################
|
||||
LOG () {
|
||||
echo -e "$1" 1>&2
|
||||
}
|
||||
|
||||
usage () {
|
||||
echo "Usage: ${PRG} [-h|-v|-g] [-m {NONE|FOOTER|ATTACHMENT|BOTH}] mbox"
|
||||
exit 1
|
||||
}
|
||||
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-h*) usage;;
|
||||
-v*) "${eMailShrinker}" -v; exit;;
|
||||
-g) DEBUG="-g"; shift;;
|
||||
-s) SIMULATE="echo"; shift;;
|
||||
-m) shift; ATTACH_MODE="$1"; shift;;
|
||||
*) break;;
|
||||
esac
|
||||
done
|
||||
case "${ATTACH_MODE}" in
|
||||
""|NONE|FOOTER|ATTACHMENT|BOTH);;
|
||||
*) usage;;
|
||||
esac
|
||||
|
||||
[ -z "${ATTACH_MODE}" ] || ATTACH_MODE="-m ${ATTACH_MODE}"
|
||||
|
||||
[ "$#" -eq 1 ] || usage
|
||||
mbox=$(realpath "$1")
|
||||
|
||||
########################################
|
||||
# recherche des binaires
|
||||
cd $(dirname $0)
|
||||
eMailShrinker="$(realpath "./eMailShrinker")"
|
||||
[ -x "${eMailShrinker}" ] || eMailShrinker="$(realpath "../../build/out/eMailShrinker")"
|
||||
[ -x "${eMailShrinker}" ] || ( echo -e "${RED}eMailShrinker not found${NC}" ; exit)
|
||||
|
||||
########################################
|
||||
dos2unix "${mbox}"
|
||||
[ -z "${SIMULATE}" ] && DOMAINEDEPOT="$(cat config/domainedepot)"
|
||||
JIRAFEAU_URL="https://depot.${DOMAINEDEPOT}"
|
||||
JIRAFEAU_LOCAL="${JIRAFEAU_URL}"
|
||||
|
||||
TMP_DIR="$(mktemp)"
|
||||
|
||||
########################################
|
||||
# curl Jirafeau
|
||||
curlJirafeauUpdate () {
|
||||
# $1: periode
|
||||
# $2: jirafeauItemRef
|
||||
|
||||
[ -z "${SIMULATE}" ] && curl -X POST -d "u=$1" -d "h=$2" "${JIRAFEAU_LOCAL}/a.php"
|
||||
}
|
||||
|
||||
curlJirafeauSend () {
|
||||
# $1: periode
|
||||
# $2: filename
|
||||
# $3: content-type
|
||||
# $4: name
|
||||
# $5: password
|
||||
|
||||
if [ -n "${SIMULATE}" ]; then
|
||||
echo -e "TokenXXX\nCodeX"
|
||||
return
|
||||
fi
|
||||
type="type=$3;"
|
||||
[ -z "$3" -o "$3" = "/" ] && type=""
|
||||
LOG "curl -X POST -F \"time=$1\" -F \"key=$5\" -F \"file=@$2;${type}filename=\\\"$4\\\"\" \"${JIRAFEAU_LOCAL}/s.php\""
|
||||
curl -X POST -F "time=$1" -F "key=$5" -F "file=@$2;${type}filename=\"$4\"" "${JIRAFEAU_LOCAL}/s.php" || exit 1
|
||||
}
|
||||
|
||||
########################################
|
||||
# nettoyage
|
||||
rm -f "${TMP_DIR}" ; mkdir -p "${TMP_DIR}"
|
||||
rm -fr "${TMP_DIR}/PJ-name.txt" "${TMP_DIR}/PJ-Keys.txt" "${TMP_DIR}/PJ" "${TMP_DIR}/archive-content.txt" "${TMP_DIR}/url-to-refresh.txt" "${TMP_DIR}/new-mbox"
|
||||
|
||||
echo -e "time: $(date "+%Y-%m-%d-%H:%M:%S")\nid: $(date +%s)" > "${TMP_DIR}/archive-content.txt"
|
||||
|
||||
########################################
|
||||
# affichage de la structure de départ
|
||||
LOG " - ${BLUE}mbox: ${mbox}${NC}${YELLOW}"
|
||||
"${eMailShrinker}" -l "${mbox}"
|
||||
LOG "${NC}"
|
||||
|
||||
########################################
|
||||
# Préparation pour le cloud
|
||||
rm -f "${TMP_DIR}/last.txt"
|
||||
|
||||
########################################
|
||||
# recherche des prolongations des délais de grace
|
||||
"${eMailShrinker}" ${DEBUG} -u "${mbox}" > "${TMP_DIR}/url-to-refresh.txt"
|
||||
cat "${TMP_DIR}/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}"
|
||||
curlJirafeauUpdate "${PERIODE}" "${REMOTE_REF}"
|
||||
echo "old: ${REMOTE_REF} ${REMOTE_KEY}" >> "${TMP_DIR}/archive-content.txt"
|
||||
echo "h=${REMOTE_REF}~${REMOTE_KEY}" > "${TMP_DIR}/last.txt"
|
||||
done
|
||||
|
||||
########################################
|
||||
# extraction des pièces jointes
|
||||
"${eMailShrinker}" ${DEBUG} -s "5ki" -d "${TMP_DIR}/PJ" "${mbox}" > "${TMP_DIR}/PJ-name.txt" || exit 1
|
||||
|
||||
LOG " - ${BLUE}PJ-name: ${NC}"
|
||||
cat "${TMP_DIR}/PJ-name.txt"
|
||||
LOG
|
||||
|
||||
########################################
|
||||
# dépot des extractions dans jirafeau et récupération des codes
|
||||
cat "${TMP_DIR}/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 -M cln)
|
||||
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
|
||||
curlJirafeauSend "${PERIODE}" "${ATTACH_MEDIA}" "${ATTACH_CONTENT_TYPE}" "${ATTACH_NAME}" "${PASSWORD}" > "${TMP_DIR}/one.txt"
|
||||
|
||||
cat "${TMP_DIR}/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_DIR}/one.txt" >&2
|
||||
echo "url:"
|
||||
exit 1
|
||||
;;
|
||||
* )
|
||||
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_DIR}/archive-content.txt"
|
||||
echo "h=${JIR_TOKEN}~${PASSWORD_MD5}" > "${TMP_DIR}/last.txt"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
done
|
||||
NB_ATTACH=$(grep -e "^old: " -e "^new: " "${TMP_DIR}/archive-content.txt" | wc -l)
|
||||
if [ "${NB_ATTACH}" -gt 1 ]; then
|
||||
PASSWORD=$(apg -n 1 -m 12 -M cln)
|
||||
PASSWORD_MD5=$(echo -n ${PASSWORD} | ${MD5_CMD} | cut -d \ -f 1)
|
||||
curlJirafeauSend "${PERIODE}" "${TMP_DIR}/archive-content.txt" "text/kaz_email_archive" "archive_content" "${PASSWORD}" > "${TMP_DIR}/one.txt" || exit 1
|
||||
cat "${TMP_DIR}/one.txt" | {
|
||||
read JIR_TOKEN
|
||||
read JIR_CODE
|
||||
case "${JIR_TOKEN}" in
|
||||
"" | no | *Error* | \<* )
|
||||
LOG " - ${RED}can't upload ${TMP_DIR}/archive-content.txt${NC}"
|
||||
echo "arch: bad"
|
||||
exit 1
|
||||
;;
|
||||
* )
|
||||
LOG " - ${GREEN} upload archive-content.txt${NC}"
|
||||
echo "arch: ${JIRAFEAU_URL}/a.php?g=${JIR_TOKEN}~${PASSWORD_MD5}"
|
||||
echo "g=${JIR_TOKEN}~${PASSWORD_MD5}" > "${TMP_DIR}/last.txt"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
else
|
||||
LOG " - ${GREEN}no archive${NC}"
|
||||
echo "arch: none"
|
||||
fi
|
||||
if [ -s "${TMP_DIR}/last.txt" ]; then
|
||||
echo "cloud: ${JIRAFEAU_URL}/c.php?$(cat "${TMP_DIR}/last.txt")"
|
||||
else
|
||||
echo "cloud: none"
|
||||
fi
|
||||
|
||||
} > "${TMP_DIR}/PJ-Keys.txt"
|
||||
|
||||
LOG " - ${BLUE}PJ-Keys: ${NC}"
|
||||
cat "${TMP_DIR}/PJ-Keys.txt"
|
||||
LOG
|
||||
|
||||
LOG " - ${GREEN}ATTACH_MODE: ${ATTACH_MODE}${NC}"
|
||||
|
||||
########################################
|
||||
# substitution des pièces jointes par les codes fournis par jirafeau
|
||||
cat "${TMP_DIR}/PJ-Keys.txt" | "${eMailShrinker}" ${DEBUG} ${ATTACH_MODE} -s "5ki" "${mbox}" "${TMP_DIR}/new-mbox" || exit 1
|
||||
|
||||
########################################
|
||||
# affichage de la structure à la fin
|
||||
LOG " - ${BLUE}new-mbox:${NC}${YELLOW}"
|
||||
"${eMailShrinker}" -l "${TMP_DIR}/new-mbox" || ( LOG "${NC}" ; exit 1)
|
||||
|
||||
echo -e "\n${NC}${GREEN}${BOLD}resul in ${TMP_DIR}/new-mbox${NC}"
|
||||
exit 0
|
@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
TMP_LOG="$(mktemp)"
|
||||
|
||||
#trap "rm -rf ${TMP_LOG}" 0 1 2 3 15
|
||||
|
||||
cat > ${TMP_LOG}
|
||||
cat ${TMP_LOG}
|
@ -60,17 +60,22 @@ const string Attachment::contentIDToken ("content-id");
|
||||
const string Attachment::PLAIN ("plain");
|
||||
const string Attachment::HTML ("html");
|
||||
const string Attachment::RELATED ("related");
|
||||
const string Attachment::SIGNED ("signed");
|
||||
const string Attachment::ALTERNATIVE ("alternative");
|
||||
const string Attachment::KAZ_ATTACH_NAME ("vos-pieces-jointes-kaz-ici.htm");
|
||||
const string Attachment::MULTIPART ("multipart/");
|
||||
|
||||
const regex Attachment::nameCharsetRegEx ( ".*name\\*=\\s*([; \t]*)");
|
||||
const regex Attachment::nameRegEx ( ".*name=\\s*((\"(\\\\.|[^\\\\])*\")|[^; \t]*).*");
|
||||
const regex Attachment::boundaryRegEx (".*boundary=\\s*((\"(\\\\.|[^\\\\])*\")|[^; \t]*).*");
|
||||
|
||||
const regex Attachment::nameCharsetRegEx (".*name\\*=(.*)");
|
||||
const regex Attachment::nameRegEx (".*name=\"([^\"]*)\".*");
|
||||
// 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+"|"+SIGNED+").*");
|
||||
const regex Attachment::multiRegEx ("\\s*multipart/(mixed|"+RELATED+"|"+ALTERNATIVE+").*");
|
||||
|
||||
const string Attachment::IMG_BEGIN ("<IMG");
|
||||
const string Attachment::IMG_END (">");
|
||||
@ -125,7 +130,7 @@ Attachment::removeSection (string &content, const string &beginTag, const string
|
||||
// ================================================================================
|
||||
string
|
||||
Attachment::getSection (const string &content, const string &beginTag, const string &endTag) {
|
||||
DEF_LOG ("Attachment::getSection", "beginTag: " << beginTag << " endTag: " << endTag << " content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("Attachment::getSection", "beginTag: " << beginTag << " endTag: " << endTag << " content: " << content);
|
||||
vector<string> list;
|
||||
getSection (content, beginTag, endTag, list);
|
||||
size_t sum (0);
|
||||
@ -136,23 +141,23 @@ Attachment::getSection (const string &content, const string &beginTag, const str
|
||||
for (const string &s : list)
|
||||
result += s;
|
||||
LOG ("result: " << result);
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
Attachment::getSection (const string &content, const string &beginTag, const string &endTag, vector<string> &result) {
|
||||
DEF_LOG ("Attachment::getSection", "beginTag: " << beginTag << " endTag: " << endTag << " content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("Attachment::getSection", "beginTag: " << beginTag << " endTag: " << endTag << " content: " << content);
|
||||
for (string::size_type startPos (0);
|
||||
(startPos = caseInsensitiveFind (content, beginTag, startPos)) != string::npos;
|
||||
) {
|
||||
LOG (beginTag << ": " << startPos);
|
||||
string::size_type stopPos = caseInsensitiveFind (content, endTag, startPos);
|
||||
|
||||
LOG_BUG (stopPos == string::npos, break, "eMailShrinker: bug A3: " << endTag << " not found! at: " << startPos << endl << content.substr (0, 100) << "...");
|
||||
LOG_BUG (stopPos == string::npos, break, "eMailShrinker: bug A3: " << endTag << " not found! at: " << startPos);
|
||||
LOG ("start: " << startPos << " stop: " << stopPos);
|
||||
|
||||
LOG_BUG (startPos == stopPos, /* */, "eMailShrinker: bug A4: " << endTag << " without " << beginTag << " at: " << startPos);
|
||||
LOG_BUG (startPos == stopPos, /**/, "eMailShrinker: bug A4: " << endTag << " without " << beginTag << " at: " << startPos);
|
||||
if (startPos != stopPos) {
|
||||
startPos += beginTag.length ();
|
||||
result.push_back (content.substr (startPos, stopPos-startPos));
|
||||
@ -176,51 +181,32 @@ Attachment::getContentType () const {
|
||||
|
||||
const string
|
||||
Attachment::getAttachName () const {
|
||||
static string tokens [] = {contentTypeToken, contentDispositionToken};
|
||||
DEF_LOG ("Attachment::getAttachName", "");
|
||||
for (string token : tokens) {
|
||||
// name=
|
||||
string result = getProp (token, nameRegEx);
|
||||
removeQuote (result);
|
||||
if (result.length ()) {
|
||||
LOG ("name=: " << result);
|
||||
encodedWordDecode (result);
|
||||
return result;
|
||||
}
|
||||
// name*x=
|
||||
for (int id = 0; ; ++id) {
|
||||
string item = getProp (token, regex (".*name\\*"+to_string (id)+"=\\s*((\"(\\\\.|[^\\\\])*\")|[; \t]*).*"));
|
||||
if (item.empty ())
|
||||
break;
|
||||
result += item;
|
||||
}
|
||||
removeQuote (result);
|
||||
if (result.length ()) {
|
||||
LOG ("name*x=: " << result);
|
||||
encodedWordDecode (result);
|
||||
return result;
|
||||
}
|
||||
// name*=
|
||||
result = getProp (token, nameCharsetRegEx);
|
||||
removeQuote (result);
|
||||
if (result.length ()) {
|
||||
LOG ("name*=: " << result);
|
||||
charsetValueDecode (result);
|
||||
return result;
|
||||
}
|
||||
// name*x*=
|
||||
for (int id = 0; ; ++id) {
|
||||
string item = getProp (token, regex (".*name\\*"+to_string (id)+"\\*=\\s*([^; ]*)"));
|
||||
if (item.empty ())
|
||||
break;
|
||||
result += item;
|
||||
}
|
||||
removeQuote (result);
|
||||
if (result.length ()) {
|
||||
LOG ("name*x*=: " << result);
|
||||
encodedWordDecode (result);
|
||||
return result;
|
||||
}
|
||||
string result = getProp (contentTypeToken, nameRegEx);
|
||||
if (result.length ()) {
|
||||
LOG ("name=: " << result);
|
||||
encodedWord (result);
|
||||
return result;
|
||||
}
|
||||
result = getProp (contentTypeToken, nameCharsetRegEx);
|
||||
if (result.length ()) {
|
||||
LOG ("name*=: " << result);
|
||||
charsetValue (result);
|
||||
return result;
|
||||
}
|
||||
// XXX il faut composer s'il y a plusieurs ligne filename*x=
|
||||
result = getProp (contentDispositionToken, nameRegEx);
|
||||
if (result.length ()) {
|
||||
LOG ("filename=: " << result);
|
||||
encodedWord (result);
|
||||
return result;
|
||||
}
|
||||
// XXX il faut composer s'il y a plusieurs ligne filename*x*=
|
||||
result = getProp (contentDispositionToken, nameRegEx);
|
||||
if (result.length ()) {
|
||||
LOG ("filename*=: " << result);
|
||||
charsetValue (result);
|
||||
return result;
|
||||
}
|
||||
return getUnknown (getContentType ());
|
||||
}
|
||||
@ -274,7 +260,7 @@ Attachment::isDefProp (const string &token, const string &val) const {
|
||||
if (it == env.end ())
|
||||
return false;
|
||||
// XXX case insensitive ??
|
||||
return caseInsensitiveFind (it->second, val) != string::npos;
|
||||
return it->second.find (val) != string::npos;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
@ -287,8 +273,6 @@ Attachment::Attachment (ifstream &mbox, const int &level, const streamoff beginI
|
||||
toExtract (false),
|
||||
toUpdate (false),
|
||||
toDisclaim (false),
|
||||
isKazAttachment (false),
|
||||
isSigned (false),
|
||||
boundaryMiddleSize (0) {
|
||||
DEF_LOG ("Attachment::Attachment", "curPos: " << curPos << " level: " << level);
|
||||
readMime (mbox, curPos);
|
||||
@ -296,38 +280,6 @@ Attachment::Attachment (ifstream &mbox, const int &level, const streamoff beginI
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
/*! lower case "var in string " VAR=val; ..." */
|
||||
inline string
|
||||
cleanString (string line) {
|
||||
DEF_LOG ("Attachment::cleanString", "line: " << line.substr (0, 100) << "...");
|
||||
|
||||
static const regex findPart ("(((\"(\\\\.|[^\\\\])*\")|\\s|[^;\\\"])+;?)");
|
||||
static const regex findVarVal ("(\\s*[a-zA-Z_*-]+(\\*[0-9]+\\*)?=)(.*;?)");
|
||||
string result;
|
||||
smatch m1, m2;
|
||||
|
||||
while (regex_search (line, m1, findPart)) {
|
||||
if (m1.prefix ().length ())
|
||||
result += m1.prefix (); // XXX when \" on multi-lines
|
||||
string part (m1[1]);
|
||||
LOG ("part: " << part);
|
||||
if (regex_search (part, m2, findVarVal) && !m2.prefix ().length ()) {
|
||||
string id (m2[1]);
|
||||
LOG ("id: " << id);
|
||||
toLower (id);
|
||||
result += id;
|
||||
result += m2[3];
|
||||
} else
|
||||
result += part;
|
||||
line = m1.suffix ();
|
||||
}
|
||||
if (!line.empty () && line[line.size() - 1] == '\r')
|
||||
line = line.substr (0, line.size () - 1);
|
||||
result += line;
|
||||
LOG ("result: " << result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
Attachment::readMime (ifstream &mbox, streamoff &curPos) {
|
||||
DEF_LOG ("Attachment::readMime", "curPos: " << curPos);
|
||||
@ -336,16 +288,16 @@ Attachment::readMime (ifstream &mbox, streamoff &curPos) {
|
||||
for (; getline (mbox, line); ) {
|
||||
LOG ("pos: " << curPos << " line: " << line);
|
||||
curPos += line.length () + 1;
|
||||
if (line.empty () || "\r" == line)
|
||||
if (line.empty ())
|
||||
break;
|
||||
if (line[0] == ' ' || line[0] == '\t') {
|
||||
if (lastVar.empty ()) {
|
||||
|
||||
LOG_BUG (true, /* */, "eMailShrinker: bug A5: not compliant MIME. pos: " << (curPos - (line.length () + 1)) << " line: " << line);
|
||||
LOG_BUG (true, /**/, "eMailShrinker: bug A5: not compliant MIME. pos: " << (curPos - (line.length () + 1)) << " line: " << line);
|
||||
} else {
|
||||
LOG ("add line to var: " << line);
|
||||
env.find (lastVar)->second += cleanString (line);
|
||||
LOG ("new val(a): <" << lastVar << " <=> " << env.find (lastVar)->second << ">");
|
||||
env.find (lastVar)->second += line;
|
||||
LOG ("new val: " << env.find (lastVar)->second);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -354,11 +306,8 @@ Attachment::readMime (ifstream &mbox, streamoff &curPos) {
|
||||
lastVar = line.substr (0, colonPos);
|
||||
toLower (lastVar);
|
||||
LOG ("find var: " << lastVar);
|
||||
++colonPos;
|
||||
if (line.length () >= colonPos && line [colonPos] == ' ')
|
||||
++colonPos;
|
||||
string val (cleanString (line.length () >= colonPos ? line.substr (colonPos) : ""));
|
||||
LOG ("new var(b): <" << lastVar << " <=> " << val << ">");
|
||||
string val (line.length () >= colonPos+2 ? line.substr (colonPos+2) : ""); // XXX check RFC " " after ": "
|
||||
LOG ("new var: " << lastVar << " <=> " << val);
|
||||
env [lastVar] = val;
|
||||
}
|
||||
}
|
||||
@ -366,18 +315,11 @@ Attachment::readMime (ifstream &mbox, streamoff &curPos) {
|
||||
|
||||
contentPos = curPos;
|
||||
cid = getProp (contentIDToken, cidDefRegEx);
|
||||
|
||||
if (caseInsensitiveFind (getContentType (), MULTIPART) != string::npos) {
|
||||
string multiProp = getProp (contentTypeToken, multiRegEx);
|
||||
if (SIGNED == multiProp)
|
||||
isSigned = true;
|
||||
boundary = getProp (contentTypeToken, boundaryRegEx);
|
||||
removeQuote (boundary);
|
||||
LOG ("boundary: " << boundary);
|
||||
if (boundary.length ()) {
|
||||
boundary = "--"+boundary+"--";
|
||||
boundaryMiddleSize = boundary.length () - 2;
|
||||
}
|
||||
boundary = getProp (contentTypeToken, boundaryRegEx);
|
||||
LOG ("boundary: " << boundary);
|
||||
if (boundary.length ()) {
|
||||
boundary = "--"+boundary+"--";
|
||||
boundaryMiddleSize = boundary.length () - 2;
|
||||
}
|
||||
LOG ("readMime contentPos: " << contentPos << " cid: " << cid << " boundary: " << boundary);
|
||||
}
|
||||
@ -466,50 +408,34 @@ Attachment::markDisclaim (bool &plainMarked, bool &htmlMarked) {
|
||||
|
||||
// ================================================================================
|
||||
bool
|
||||
Attachment::markSignificant (const string &parentMultiProp, const bool &parentSigned, const streamoff &minAttachSize, ifstream &mbox, vector<Attachment *> &allMarkedPtrs) {
|
||||
Attachment::markSignificant (const string &parentMultiProp, const streamoff &minAttachSize, ifstream &mbox, vector<Attachment *> &allMarkedPtrs) {
|
||||
DEF_LOG ("Attachment::markSignificant", "parentMultiProp: " << parentMultiProp << " minAttachSize: " << minAttachSize);
|
||||
isSigned |= parentSigned;
|
||||
string textProp = getProp (contentTypeToken, textRegEx);
|
||||
bool cantBeExtract ((parentMultiProp == ALTERNATIVE && (textProp == PLAIN || textProp == HTML)) ||
|
||||
(parentMultiProp == RELATED && textProp == HTML));
|
||||
string multiProp = getProp (contentTypeToken, multiRegEx);
|
||||
for (Attachment &sub : subAttachements)
|
||||
cantBeExtract |= sub.markSignificant (multiProp, parentSigned || isSigned, minAttachSize, mbox, allMarkedPtrs);
|
||||
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);
|
||||
EmbeddedData::fillEmbeddedData (imgs, minAttachSize, embeddedData);
|
||||
if (embeddedData.size ())
|
||||
toUpdate = true;
|
||||
}
|
||||
string content = getContent (mbox);
|
||||
vector<string> imgs;
|
||||
getSection (content, IMG_BEGIN, IMG_END, imgs);
|
||||
EmbeddedData::fillEmbeddedData (imgs, minAttachSize, embeddedData);
|
||||
if (embeddedData.size ())
|
||||
toUpdate = true;
|
||||
}
|
||||
cantBeExtract |= toUpdate;
|
||||
if (boundary.empty () && getSize () >= minAttachSize && !cantBeExtract)
|
||||
cantBeExtract = toExtract = true;
|
||||
if (toExtract || toUpdate || toDisclaim || isKazAttachment)
|
||||
cantBeExtract = toExtract = true; // XXX cantBeExtract ?
|
||||
if (toExtract || toUpdate || toDisclaim)
|
||||
allMarkedPtrs.push_back (this);
|
||||
return cantBeExtract;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
string
|
||||
Attachment::getMime (ifstream &mbox) const {
|
||||
DEF_LOG ("Attachment::getMime", "beginPos: " << beginPos << " contentPos: " << contentPos);
|
||||
string mime;
|
||||
mime.resize (contentPos-beginPos);
|
||||
mbox.seekg (beginPos, ios::beg);
|
||||
mbox.read (&mime[0], contentPos-beginPos);
|
||||
return mime;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
string
|
||||
Attachment::getContent (ifstream &mbox) const {
|
||||
DEF_LOG ("Attachment::getContent", "contentPos: " << contentPos << " endPos: " << endPos);
|
||||
DEF_LOG ("Attachment::getContent", "contentPos: " << contentPos);
|
||||
string content;
|
||||
content.resize (endPos-contentPos);
|
||||
mbox.seekg (contentPos, ios::beg);
|
||||
@ -524,7 +450,7 @@ Attachment::getContent (ifstream &mbox) const {
|
||||
// ================================================================================
|
||||
void
|
||||
Attachment::println (ofstream &outbox, string content) const {
|
||||
DEF_LOG ("Attachment::println", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("Attachment::println", "content: " << content);
|
||||
if (isBase64Encoding ())
|
||||
base64Encode (content);
|
||||
if (isQuotedPrintableEnconding ())
|
||||
@ -567,9 +493,7 @@ Attachment::replaceEmbedded (string &content) const {
|
||||
ostream&
|
||||
kaz::operator << (ostream& os, const Attachment& attachment) {
|
||||
string prop, sep;
|
||||
if (attachment.isSigned) { prop += sep+"signed"; sep = ", "; }
|
||||
if (attachment.isKazAttachment) { prop += sep+"kazDisclaim"; sep = ", "; }
|
||||
if (attachment.toExtract) { prop += sep+"to extract"; sep = ", "; }
|
||||
if (attachment.toExtract) { prop = "to extract"; sep = ", "; }
|
||||
if (attachment.toUpdate) { prop += sep+"need update"; sep = ", "; }
|
||||
if (attachment.toDisclaim) { prop += sep+"need diclaim"; sep = ", "; }
|
||||
if (attachment.embeddedData.size ()) { prop += sep+"embeddedData"; }
|
||||
|
@ -42,10 +42,6 @@
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "version.hpp"
|
||||
#include "kazDebug.hpp"
|
||||
#include "kazMisc.hpp"
|
||||
#include "SizeArg.hpp"
|
||||
@ -61,12 +57,13 @@ static const string TMPL_FILENAME ("{{FILENAME}}");
|
||||
static const string CID ("cid:");
|
||||
|
||||
// "l=/" => v1 compatibility
|
||||
static const regex archiveURLRegex (".*(([&?]g=)|([&?]l=/)).*");
|
||||
static const regex archiveURLSignature (".*(([&?]g=)|([&?]l=/)).*");
|
||||
|
||||
|
||||
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 (version "+LAST_VERSION_NUM+"))");
|
||||
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. "
|
||||
@ -74,7 +71,6 @@ static const string KAZ_PLAIN_WARNING ("Attention : Kaz a dépollué ce
|
||||
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 KAZ_PLAIN_DOWLOAD_CLOUD ("Vous pouvez classer les pièces jointes dans votre cloud là :");
|
||||
|
||||
static const string HEAD ("<head>");
|
||||
static const string HEAD_END ("</head>");
|
||||
@ -87,7 +83,6 @@ 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>");
|
||||
|
||||
@ -95,19 +90,14 @@ 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éponse si vous voulez transmettre les documents précédents (version "+LAST_VERSION_NUM+"))");
|
||||
static const string KAZ_HTML_DONT_TOUCH ("(conservez cette partie intacte dans votre réponse si vous voulez transmettre les documents précédents)");
|
||||
static const string KAZ_HTML_DOWLOAD_ONE ("Vos pièces jointes sont à télécharger individuellement ici :");
|
||||
static const string KAZ_HTML_DOWLOAD_OTHER ("(Contenu dans des messages précédents)");
|
||||
static const string KAZ_HTML_DOWLOAD_ALL ("Vous pouvez télécharger l'ensemble dans une archive là :");
|
||||
static const string KAZ_HTML_DOWLOAD_CLOUD ("Vous pouvez classer les pièces jointes dans votre cloud là :");
|
||||
static const string KAZ_HTML_ARCHIVE ("archive");
|
||||
static const string KAZ_HTML_CLOUD ("cloud");
|
||||
|
||||
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");
|
||||
|
||||
|
||||
// ================================================================================
|
||||
@ -115,10 +105,8 @@ vector <string>
|
||||
Attachment::stringsToUpdate ({KAZ_PLAIN_START, "\""+CID});
|
||||
|
||||
// ================================================================================
|
||||
const string MainAttachment::templatePlainAddLink (" * "+TMPL_FILENAME+" < "+TMPL_DOWNLOAD+" >\n");
|
||||
const string MainAttachment::templatePlainAllLink ("\n * "+KAZ_PLAIN_DOWLOAD_ALL+" < "+TMPL_DOWNLOAD+" >\n");
|
||||
const string MainAttachment::templatePlainCloudLink ("\n * "+KAZ_PLAIN_DOWLOAD_CLOUD+" < "+TMPL_DOWNLOAD+" >\n");
|
||||
const string MainAttachment::templatePlainFooter ("\n\n"+KAZ_WEB_SITE+"\n\n"+KAZ_PLAIN_WARNING+"\n"+KAZ_PLAIN_HR+"\n"+KAZ_PLAIN_STOP+"\n\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\">"
|
||||
@ -127,70 +115,12 @@ const string MainAttachment::templateHtmlHeader (KAZ_HTML_START+"<p style=\"cle
|
||||
const string MainAttachment::templateHtmlAddLink (LI_ONE+"<a "+HREF_ONE+TMPL_DOWNLOAD+"\">"+TMPL_FILENAME+"</a>"+LI_END+"\n");
|
||||
const string MainAttachment::templateHtmlOtherLink ("</ul>"+KAZ_HTML_DOWLOAD_OTHER+"<ul>\n");
|
||||
const string MainAttachment::templateHtmlAllLink ("</ul><ul>"+LI_ALL+KAZ_HTML_DOWLOAD_ALL+" <a href=\""+TMPL_DOWNLOAD+"\">"+KAZ_HTML_ARCHIVE+"</a>"+LI_END+"\n");
|
||||
const string MainAttachment::templateHtmlCloudLink ("</ul><ul>"+LI_ALL+KAZ_HTML_DOWLOAD_CLOUD+" <a href=\""+TMPL_DOWNLOAD+"\">"+KAZ_HTML_CLOUD+"</a>"+LI_END+"\n");
|
||||
const string MainAttachment::templateHtmlFooter ("</ul></p>\n"
|
||||
"<p class=\"msg\"><a class=\"kaz\" href=\""+KAZ_WEB_SITE+"\"> "+KAZ_WEB_SITE+" </a></p></div>\n"
|
||||
"<hr><p style=\"font-size:10px; color:#969696;\">"+KAZ_PLAIN_STOP+"</p>"+KAZ_HTML_STOP+"\n\n");
|
||||
"<hr><p style=\"font-size:10px; color:#969696;\">"+KAZ_PLAIN_STOP+"</p>"+KAZ_HTML_STOP+"\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;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
const string
|
||||
kaz::headerTypeLabels[] = {
|
||||
"Same", "Mixed", "MainPlain"
|
||||
};
|
||||
const map<string, HeaderType>
|
||||
kaz::headerTypeMap = boost::assign::map_list_of
|
||||
("same", SAME)
|
||||
("mixed", MIXED)
|
||||
("mainplain", MAIN_PLAIN)
|
||||
;
|
||||
ostream &
|
||||
kaz::operator << (ostream &out, const HeaderType &headerType) {
|
||||
//BOOST_ASSERT (treeType >= MIN && treeType <= ALPHA);
|
||||
return out << headerTypeLabels [headerType];
|
||||
}
|
||||
istream &
|
||||
kaz::operator >> (istream &in, HeaderType &headerType) {
|
||||
string token;
|
||||
in >> token;
|
||||
auto pos = headerTypeMap.find (boost::algorithm::to_lower_copy (token));
|
||||
if (pos == headerTypeMap.end ())
|
||||
in.setstate (ios_base::failbit);
|
||||
else
|
||||
headerType = pos->second;
|
||||
return in;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
MainAttachment::copy (ifstream &mbox, ofstream &outbox, const streamoff &begin, const streamoff &end) {
|
||||
@ -204,18 +134,6 @@ MainAttachment::copy (ifstream &mbox, ofstream &outbox, const streamoff &begin,
|
||||
outbox.flush ();
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
MainAttachment::readDownloadUrl (string &url) {
|
||||
DEF_LOG ("MainAttachment::readDownloadUrl", "");
|
||||
url = "";
|
||||
string line;
|
||||
getline (cin, line);
|
||||
LOG ("get URL: " << line);
|
||||
LOG_BUG (line.rfind ("url: ", 0) != 0, return, "eMailShrinker: bug M11: no download link. (line: " << line << ")");
|
||||
url = line.substr (5);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
MainAttachment::readArchiveUrl () {
|
||||
@ -223,9 +141,8 @@ MainAttachment::readArchiveUrl () {
|
||||
archiveDownloadURL.clear ();
|
||||
string line;
|
||||
getline (cin, line);
|
||||
LOG ("get arch: " << line);
|
||||
LOG_BUG (line.rfind ("arch: ", 0) != 0, return, "eMailShrinker: bug M9: no archive link. (line: " << line << ")");
|
||||
LOG_BUG (line.rfind ("arch: bad", 0) == 0, return, "eMailShrinker: bug M10: bad archive link. (line: " << line << ")");
|
||||
LOG_BUG (line.rfind ("arch: ", 0) != 0, return, "eMailShrinker: bug ZZ: no archive link. (line: " << line << ")");
|
||||
LOG_BUG (line.rfind ("arch: bad", 0) == 0, return, "eMailShrinker: bug ZZ: bad archive link. (line: " << line << ")");
|
||||
if (line.rfind ("arch: none", 0) == 0)
|
||||
return;
|
||||
archiveDownloadURL = line.substr (6);
|
||||
@ -233,17 +150,14 @@ MainAttachment::readArchiveUrl () {
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
MainAttachment::readCloudUrl () {
|
||||
cloudDownloadURL.clear ();
|
||||
DEF_LOG ("MainAttachment::readCloudUrl", "");
|
||||
MainAttachment::readDownloadUrl (string &url) {
|
||||
DEF_LOG ("MainAttachment::readDownloadUrl", "");
|
||||
url = "";
|
||||
string line;
|
||||
getline (cin, line);
|
||||
LOG ("get cloud: " << line);
|
||||
LOG_BUG (line.rfind ("cloud: ", 0) != 0, return, "eMailShrinker: bug M13: no cloud link. (line: " << line << ")");
|
||||
LOG_BUG (line.rfind ("cloud: bad", 0) == 0, return, "eMailShrinker: bug M14: bad cloud link. (line: " << line << ")");
|
||||
if (line.rfind ("cloud: none", 0) == 0)
|
||||
return;
|
||||
// XXX wait new version // cloudDownloadURL = line.substr (7);
|
||||
LOG ("get URL: " << line);
|
||||
LOG_BUG (line.rfind ("url: ", 0) != 0, return, "eMailShrinker: bug ZZ: no download link. (line: " << line << ")");
|
||||
url = line.substr (5);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
@ -265,8 +179,8 @@ MainAttachment::addLink (string &plain, string &html, const string &url, const s
|
||||
plain += plainNewOneLink;
|
||||
string htmlNewOneLink (templateHtmlAddLink);
|
||||
string codedUrl (url);
|
||||
// pb &
|
||||
// replaceAll (codedUrl, "&", "&");
|
||||
// XXX amp ?
|
||||
//replaceAll (codedUrl, "&", "&");
|
||||
replaceAll (htmlNewOneLink, TMPL_DOWNLOAD, codedUrl);
|
||||
replaceAll (htmlNewOneLink, TMPL_FILENAME, name);
|
||||
html += htmlNewOneLink;
|
||||
@ -275,13 +189,13 @@ MainAttachment::addLink (string &plain, string &html, const string &url, const s
|
||||
// ================================================================================
|
||||
void
|
||||
MainAttachment::getDisclaim (string &plain, string &html) const {
|
||||
DEF_LOG ("MainAttachment::getDisclaim", "");
|
||||
DEF_LOG ("Attachment::getDisclaim", "");
|
||||
plain = html = "";
|
||||
|
||||
int linkCount (0);
|
||||
string plainNewLinks, htmlNewLinks;
|
||||
for (Attachment *attachP : allMarkedPtrs) {
|
||||
if (attachP->isSigned || !attachP->toExtract)
|
||||
if (!attachP->toExtract)
|
||||
continue;
|
||||
addLink (plainNewLinks, htmlNewLinks, attachP->downloadUrl, attachP->getAttachName ());
|
||||
++linkCount;
|
||||
@ -290,7 +204,7 @@ MainAttachment::getDisclaim (string &plain, string &html) const {
|
||||
// previousLinks.erase (attachP->downloadUrl);
|
||||
}
|
||||
for (Attachment *attachP : allMarkedPtrs) {
|
||||
if (attachP->isSigned || !attachP->embeddedData.size ())
|
||||
if (!attachP->embeddedData.size ())
|
||||
continue;
|
||||
for (EmbeddedData &embedded : attachP->embeddedData) {
|
||||
addLink (plainNewLinks, htmlNewLinks, embedded.downloadUrl, embedded.name);
|
||||
@ -307,10 +221,10 @@ MainAttachment::getDisclaim (string &plain, string &html) const {
|
||||
return;
|
||||
}
|
||||
|
||||
plain = "\n"+KAZ_PLAIN_START+"\n\n"+KAZ_PLAIN_HR+"\n"+KAZ_PLAIN_DONT_TOUCH+"\n\n"+KAZ_PLAIN_DOWLOAD_ONE+"\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_WARNING+"\r\n\r\n"+KAZ_PLAIN_DOWLOAD_ONE+"\r\n"+plainNewLinks;
|
||||
html = templateHtmlHeader+htmlNewLinks;
|
||||
if (previousLinks.size ()) {
|
||||
plain += "\n"+KAZ_PLAIN_DOWLOAD_OTHER+"\n"+plainOldLinks;
|
||||
plain += "\r\n"+KAZ_PLAIN_DOWLOAD_OTHER+"\r\n"+plainOldLinks;
|
||||
html += templateHtmlOtherLink+htmlOldLinks;
|
||||
}
|
||||
if (linkCount > 1 && archiveDownloadURL.length ()) {
|
||||
@ -321,16 +235,8 @@ MainAttachment::getDisclaim (string &plain, string &html) const {
|
||||
replaceAll (allHtmlLinks, TMPL_DOWNLOAD, archiveDownloadURL);
|
||||
html += allHtmlLinks;
|
||||
}
|
||||
if (cloudDownloadURL.length ()) {
|
||||
string cloudPlainLinks (templatePlainCloudLink);
|
||||
replaceAll (cloudPlainLinks, TMPL_DOWNLOAD, cloudDownloadURL);
|
||||
plain += cloudPlainLinks;
|
||||
string cloudHtmlLinks (templateHtmlCloudLink);
|
||||
replaceAll (cloudHtmlLinks, TMPL_DOWNLOAD, cloudDownloadURL);
|
||||
html += cloudHtmlLinks;
|
||||
}
|
||||
html += templateHtmlFooter+"\n";
|
||||
plain += templatePlainFooter+"\n";
|
||||
html += templateHtmlFooter+"\r\n";
|
||||
plain += "\r\n\r\n"+KAZ_WEB_SITE+"\r\n"+KAZ_PLAIN_HR+"\r\n"+KAZ_PLAIN_STOP+"\r\n";
|
||||
// & => & done
|
||||
LOG ("plain: " << plain);
|
||||
LOG ("html: " << html);
|
||||
@ -339,21 +245,21 @@ MainAttachment::getDisclaim (string &plain, string &html) const {
|
||||
// ================================================================================
|
||||
void
|
||||
MainAttachment::addPrevious (const string &href, const string &name, const bool &trust) {
|
||||
DEF_LOG ("MainAttachment::addPrevious", "href: " << href << " name: " << name);
|
||||
DEF_LOG ("Attachment::addPrevious", "href: " << href << " name: " << name);
|
||||
const string oldVal = previousLinks [href];
|
||||
if (name.empty ())
|
||||
return;
|
||||
if (oldVal.length () && name.length () && !trust)
|
||||
return;
|
||||
previousLinks.erase (href);
|
||||
previousLinks [href] = regex_replace (name, regex (R"([\t\n\"]+|(\\\")|(>\s*))"), "");
|
||||
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 ("MainAttachment::extractedPlainKAZ", "extractedPlainKAZ: " << extractedPlainKAZ);
|
||||
DEF_LOG ("Attachment::extractedPlainKAZ", "extractedPlainKAZ: " << extractedPlainKAZ);
|
||||
for (string::size_type startPos (0);
|
||||
(startPos = extractedPlainKAZ.find ("http", startPos)) != string::npos;
|
||||
) {
|
||||
@ -378,7 +284,7 @@ MainAttachment::extractLinks (const string &extractedPlainKAZ) {
|
||||
string name;
|
||||
|
||||
if (startName != string::npos) {
|
||||
name = string (extractedPlainKAZ, startName+2, stopName -startName-2);
|
||||
name = string (extractedPlainKAZ, startName+3, stopName - startName - 3);
|
||||
// skip [> \r\n\t]
|
||||
string::size_type nextPos = name.find_first_not_of ("[>< \t\r\n\"]");
|
||||
if (nextPos != string::npos)
|
||||
@ -398,7 +304,7 @@ MainAttachment::extractLinks (const string &extractedPlainKAZ) {
|
||||
void
|
||||
MainAttachment::extractLinks (const vector<string> &liOne) {
|
||||
// html text => "<li ...><a href="url">name</a>"
|
||||
DEF_LOG ("MainAttachment::extractedPlainKAZ", "liOne.size: " << liOne.size ());
|
||||
DEF_LOG ("Attachment::extractedPlainKAZ", "liOne.size: " << liOne.size ());
|
||||
for (const string &one : liOne) {
|
||||
if (caseInsensitiveFind (one, CLASS_ONE) == string::npos)
|
||||
continue;
|
||||
@ -429,39 +335,30 @@ MainAttachment::extractLinks (const vector<string> &liOne) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainAttachment::extractPreviousKAZ (string &extractedPlainKAZ, string &extractedHtmlKAZ, ifstream &mbox, const Attachment &attach) {
|
||||
DEF_LOG ("MainAttachment::extractPreviousKAZ", "attach:" << attach);
|
||||
if (!(attach.toUpdate || attach.isKazAttachment)) // isKazAttachment => toUpdate
|
||||
return;
|
||||
string textProp = attach.getProp (contentTypeToken, textRegEx);
|
||||
if (textProp.empty ())
|
||||
return;
|
||||
string content (attach.getContent (mbox));
|
||||
replaceAll (content, "&", "&");
|
||||
if (textProp == PLAIN) {
|
||||
LOG (PLAIN);
|
||||
extractedPlainKAZ += attach.getSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
|
||||
}
|
||||
if (textProp == HTML) {
|
||||
LOG (HTML);
|
||||
string section = attach.getSection (content, KAZ_HTML_START, KAZ_HTML_STOP);
|
||||
section += attach.getSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
|
||||
// update href from HTML attachments
|
||||
extractedHtmlKAZ += section;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainAttachment::extractPreviousKAZ (ifstream &mbox) {
|
||||
DEF_LOG ("MainAttachment::extractPreviousKAZ", "");
|
||||
string extractedPlainKAZ, extractedHtmlKAZ;
|
||||
if (boundary.empty ())
|
||||
extractPreviousKAZ (extractedPlainKAZ, extractedHtmlKAZ, mbox, *this);
|
||||
else
|
||||
for (const Attachment *attachP : allMarkedPtrs)
|
||||
extractPreviousKAZ (extractedPlainKAZ, extractedHtmlKAZ, mbox, *attachP);
|
||||
|
||||
for (const Attachment *attachP : allMarkedPtrs) {
|
||||
if (!attachP->toUpdate || isBase64Encoding ())
|
||||
continue;
|
||||
string textProp = attachP->getProp (contentTypeToken, textRegEx);
|
||||
if (textProp.empty ())
|
||||
continue;
|
||||
string content (attachP->getContent (mbox));
|
||||
if (textProp == PLAIN) {
|
||||
LOG (PLAIN);
|
||||
extractedPlainKAZ += attachP->getSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
|
||||
}
|
||||
if (textProp == HTML) {
|
||||
LOG (HTML);
|
||||
string section = attachP->getSection (content, KAZ_HTML_START, KAZ_HTML_STOP);
|
||||
section += attachP->getSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
|
||||
// update href from HTML attachments
|
||||
replaceAll (section, "&", "&");
|
||||
extractedHtmlKAZ += section;
|
||||
}
|
||||
}
|
||||
LOG ("extractedPlainKAZ: "<< extractedPlainKAZ);
|
||||
extractLinks (extractedPlainKAZ);
|
||||
|
||||
@ -478,81 +375,20 @@ MainAttachment::extractPreviousKAZ (ifstream &mbox) {
|
||||
|
||||
void
|
||||
MainAttachment::removePreviousArchive () {
|
||||
DEF_LOG ("MainAttachment::removePreviousArchive", "");
|
||||
vector<string> toRemove;
|
||||
for (map <string, string>::const_iterator it = previousLinks.begin (); it != previousLinks.end (); ++it) {
|
||||
const string key (it->first);
|
||||
if (regex_match (key, archiveURLRegex))
|
||||
if (regex_match (key, archiveURLSignature))
|
||||
toRemove.push_back (key);
|
||||
}
|
||||
for (string old : toRemove)
|
||||
previousLinks.erase (old);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void MainAttachment::rewriteHeaders (ifstream &mbox, ofstream &outbox, const HeaderType &headerType) {
|
||||
DEF_LOG ("MainAttachment::rewriteHeaders", "headerType: " << headerType);
|
||||
switch (headerType) {
|
||||
case SAME:
|
||||
copy (mbox, outbox, 0, contentPos);
|
||||
return;
|
||||
case MAIN_PLAIN:
|
||||
break;
|
||||
case MIXED:
|
||||
if (boost::iequals (getContentType (), "multipart/mixed")) {
|
||||
copy (mbox, outbox, 0, contentPos);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
string mime (getMime (mbox));
|
||||
mime.insert (0, "\n");
|
||||
string::size_type startPos = (0);
|
||||
// remove previous content-type at begin of ligne (after a "\n")
|
||||
for (string token : {string ("content-transfer-encoding"),
|
||||
Attachment::contentTypeToken}) {
|
||||
LOG ("token:" << token);
|
||||
startPos = caseInsensitiveFind (mime, string ("\n")+token);
|
||||
if (startPos == string::npos)
|
||||
continue;
|
||||
for (string::size_type stopPos (startPos+1);
|
||||
(stopPos = mime.find ("\n", stopPos)) != string::npos;
|
||||
) {
|
||||
if (string (" \t").find (mime [stopPos+1]) == string::npos) {
|
||||
// not wrap after
|
||||
movedContentType += mime.substr (startPos+1, stopPos-startPos);
|
||||
mime.erase (startPos, stopPos-startPos);
|
||||
break;
|
||||
}
|
||||
// merge wrap lines
|
||||
// find next endl
|
||||
++stopPos;
|
||||
}
|
||||
}
|
||||
string contentType (KAZ_EMPTY_TEXT_PLAIN);
|
||||
switch (headerType) {
|
||||
case SAME: /* no way */ break;
|
||||
case MAIN_PLAIN: contentType = KAZ_EMPTY_TEXT_PLAIN; break;
|
||||
case MIXED:
|
||||
addedBoundary = "__KAZ__"+boundaryGen (40);
|
||||
contentType = "Content-Type: multipart/mixed; boundary=\""+addedBoundary+"\"\n";
|
||||
addedBoundary = "--"+addedBoundary+"--";
|
||||
addedBoundaryMiddleSize = addedBoundary.length () - 2;
|
||||
}
|
||||
// skip '\n'
|
||||
++startPos;
|
||||
if (startPos >= mime.length ())
|
||||
startPos = mime.length () - 1;
|
||||
mime.insert (startPos, contentType);
|
||||
outbox << mime.substr (1) << endl << flush;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
MainAttachment::MainAttachment (ifstream &mbox)
|
||||
: Attachment (mbox, initTmpLevel (), 0, initTmpPos ()),
|
||||
emptyEMail (false),
|
||||
previousKazAttachment (false) {
|
||||
forceMainText (false) {
|
||||
DEF_LOG ("MainAttachment::MainAttachment", "");
|
||||
string line;
|
||||
for (; getline (mbox, line); )
|
||||
@ -566,8 +402,8 @@ 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 ("", isSigned, minAttachSize, mbox, allMarkedPtrs);
|
||||
forceMainText = ! (plainMarked || htmlMarked);
|
||||
Attachment::markSignificant ("", minAttachSize, mbox, allMarkedPtrs);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
@ -610,7 +446,7 @@ MainAttachment::extract (ifstream &mbox, const SizeArg &minSize) const {
|
||||
int attachCount (0);
|
||||
string dirName, mediaName;
|
||||
for (Attachment *attachP : allMarkedPtrs) {
|
||||
if (attachP->isSigned || attachP->isKazAttachment || !attachP->toExtract)
|
||||
if (!attachP->toExtract)
|
||||
continue;
|
||||
newPjEntry (attachCount, attachP->getContentType (), attachP->getAttachName (), dirName, mediaName);
|
||||
++attachCount;
|
||||
@ -661,7 +497,7 @@ MainAttachment::extract (ifstream &mbox, const SizeArg &minSize) const {
|
||||
cout << dirName << endl;
|
||||
}
|
||||
for (Attachment *attachP : allMarkedPtrs) {
|
||||
if (attachP->isSigned || !attachP->embeddedData.size ())
|
||||
if (!attachP->embeddedData.size ())
|
||||
continue;
|
||||
string content = attachP->getContent (mbox);
|
||||
vector<string> imgs;
|
||||
@ -684,25 +520,16 @@ MainAttachment::extract (ifstream &mbox, const SizeArg &minSize) const {
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
/*!
|
||||
Régle à appliquer dans le cas où Kaz ajoute son cartouche et que le corps principale n'est pas multipart :
|
||||
|
||||
<table>
|
||||
<tr><th>src</th><th>FOOTER</th><th>BOTH</th><th>ATTCH</th></tr>
|
||||
<tr><th>text/plain</th><td>OK</td><td>mute multi</td><td>mute multi</td></tr>
|
||||
<tr><th>empty mail</th><td>mute plain</td><td>mute multi</td><td>mute html</td></tr>
|
||||
</table>
|
||||
*/
|
||||
void
|
||||
MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize, AttachMode attachMode) {
|
||||
DEF_LOG ("MainAttachment::substitute", "minSize: " << minSize << " AttachMode: " << attachMode);
|
||||
MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize) {
|
||||
DEF_LOG ("MainAttachment::substitute", "minSize: " << minSize);
|
||||
|
||||
// setup
|
||||
// preparation
|
||||
extractPreviousKAZ (mbox);
|
||||
removePreviousArchive ();
|
||||
map<const string, const string> translateHtml;
|
||||
for (Attachment *attachP : allMarkedPtrs)
|
||||
if (!attachP->isSigned && attachP->toExtract && !attachP->isKazAttachment) {
|
||||
if (attachP->toExtract) {
|
||||
readDownloadUrl (attachP->downloadUrl);
|
||||
if (attachP->downloadUrl.empty ()) {
|
||||
LOG ("no change");
|
||||
@ -716,93 +543,39 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
|
||||
}
|
||||
}
|
||||
for (Attachment *attachP : allMarkedPtrs) {
|
||||
if (attachP->isSigned || !attachP->embeddedData.size ())
|
||||
if (!attachP->embeddedData.size ())
|
||||
continue;
|
||||
for (EmbeddedData &embedded : attachP->embeddedData)
|
||||
readDownloadUrl (embedded.downloadUrl);
|
||||
// XXX test empty ?
|
||||
}
|
||||
readArchiveUrl ();
|
||||
readCloudUrl ();
|
||||
removePreviousArchive ();
|
||||
string plainDisclaim, htmlDisclaim;
|
||||
getDisclaim (plainDisclaim, htmlDisclaim);
|
||||
|
||||
LOG_BUG (plainDisclaim.empty () ^ htmlDisclaim.empty (), /* */,
|
||||
"eMailShrinker: bug M8: not empty disclaim. (plainDisclaim: " << plainDisclaim.size () << " htmlDisclaim: " << htmlDisclaim.size () << ")");
|
||||
if (plainDisclaim.empty ()) {
|
||||
// no change
|
||||
cerr << "eMailShrinker: original email inchanged" << endl;
|
||||
copy (mbox, outbox, 0, endPos);
|
||||
return;
|
||||
}
|
||||
|
||||
if (boost::iequals (getContentType (), "multipart/report")) {
|
||||
// no change
|
||||
cerr << "eMailShrinker: repport email inchange" << endl;
|
||||
copy (mbox, outbox, 0, endPos);
|
||||
return;
|
||||
}
|
||||
|
||||
HeaderType headerType (SAME);
|
||||
// copy email
|
||||
switch (attachMode) {
|
||||
case NONE: LOG_BUG (true, /* */, "eMailShrinker: bug M12: nothing to do"); break;
|
||||
case FOOTER: headerType = (emptyEMail && !boundary.size ()) ? MAIN_PLAIN : SAME; break;
|
||||
case BOTH: headerType = MIXED; break;
|
||||
case ATTACHMENT: headerType = MIXED; break;
|
||||
}
|
||||
rewriteHeaders (mbox, outbox, headerType);
|
||||
streamoff curPos = contentPos;
|
||||
|
||||
if (MAIN_PLAIN == headerType) {
|
||||
LOG ("Replace old content with plain");
|
||||
string content (plainDisclaim);
|
||||
base64Encode (content);
|
||||
outbox << content << endl;
|
||||
outbox.flush ();
|
||||
return;
|
||||
}
|
||||
|
||||
// // XXX => MIXED
|
||||
// if (ATTACH_HTML == headerType) {
|
||||
// LOG ("Replace old content with html");
|
||||
// string content (plainDisclaim);
|
||||
// base64Encode (content);
|
||||
// outbox << content << endl;
|
||||
// outbox.flush ();
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (emptyEMail && (attachMode & FOOTER)) {
|
||||
// case : multi
|
||||
streamoff curPos = 0;
|
||||
if (forceMainText) {
|
||||
cerr << endl << endl << " #################### coucou " << forceMainText << " " << contentPos << " " << *this << endl;
|
||||
// check no main text
|
||||
LOG ("Force main text");
|
||||
cerr << "eMailShrinker: force main text" << endl;
|
||||
LOG_BUG (boundary.empty () || ! subAttachements.size (), /**/, "eMailShrinker: can't force add footer M9: : " << *this);
|
||||
copy (mbox, outbox, curPos, contentPos);
|
||||
curPos = contentPos;
|
||||
cerr << " #################### coucou " << curPos << endl << endl;
|
||||
string content (plainDisclaim);
|
||||
base64Encode (content);
|
||||
outbox << boundary.substr (0, boundaryMiddleSize) << endl
|
||||
outbox << boundary.substr (0, boundary.length () -2) << endl
|
||||
<< KAZ_EMPTY_TEXT_PLAIN << endl
|
||||
<< content << endl;
|
||||
outbox.flush ();
|
||||
}
|
||||
|
||||
if (movedContentType.size ()) {
|
||||
LOG ("New boundary");
|
||||
outbox << addedBoundary.substr (0, addedBoundaryMiddleSize) << endl
|
||||
<< movedContentType << endl;
|
||||
}
|
||||
|
||||
for (Attachment *attachP : allMarkedPtrs) {
|
||||
copy (mbox, outbox, curPos, attachP->beginInParent);
|
||||
outbox << endl; // force end MIME section
|
||||
LOG_BUG (attachP->toUpdate && attachP->toExtract, /* */, "eMailShrinker: bug M5: update and extract. pos: " << attachP->beginPos);
|
||||
LOG_BUG (attachP->toUpdate && attachP->toExtract, /**/, "eMailShrinker: bug M5: update and extract. pos: " << attachP->beginPos);
|
||||
|
||||
if (attachP->isSigned) {
|
||||
LOG ("don't change signed content");
|
||||
copy (mbox, outbox, attachP->beginInParent, attachP->endPos);
|
||||
|
||||
} else if (attachP->toExtract || attachP->isKazAttachment) {
|
||||
LOG ("skip Extracted or previous attachments");
|
||||
if (attachP->toExtract) {
|
||||
LOG ("skip Extracted");
|
||||
|
||||
} else if (attachP->toUpdate) {
|
||||
string textProp = attachP->getProp (contentTypeToken, textRegEx);
|
||||
@ -810,11 +583,10 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
|
||||
bool isHtml = textProp == HTML;
|
||||
bool isDisclaimer = attachP->toDisclaim;
|
||||
|
||||
LOG_BUG (isPlain && isHtml, /* */, "eMailShrinker: bug M6: plain and html: " << attachP->getContentType ());
|
||||
LOG_BUG (! (isPlain || isHtml), /* */, "eMailShrinker: bug M7: not plain or html: " << attachP->getContentType ());
|
||||
LOG_BUG (isPlain && isHtml, /**/, "eMailShrinker: bug M6: plain and html: " << attachP->getContentType ());
|
||||
LOG_BUG (! (isPlain || isHtml), /**/, "eMailShrinker: bug M7: not plain or html: " << attachP->getContentType ());
|
||||
LOG ("toUpdate: isPlain: " << isPlain << " isHtml: " << isHtml << " isDisclaimer: " << isDisclaimer);
|
||||
if (attachP != this)
|
||||
copy (mbox, outbox, attachP->beginInParent, attachP->contentPos);
|
||||
copy (mbox, outbox, attachP->beginInParent, attachP->contentPos);
|
||||
|
||||
string content = attachP->getContent (mbox);
|
||||
if (isHtml) {
|
||||
@ -844,13 +616,14 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
|
||||
}
|
||||
removeSection (content, KAZ_HTML_START, KAZ_HTML_STOP);
|
||||
removeSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
|
||||
if (caseInsensitiveFind (content, CID) != string::npos)
|
||||
// XXX case insensitive ??
|
||||
if (content.find (CID) != string::npos)
|
||||
replaceAll (content, translateHtml);
|
||||
attachP->replaceEmbedded (content);
|
||||
}
|
||||
if (isPlain)
|
||||
removeSection (content, KAZ_PLAIN_START, KAZ_PLAIN_STOP);
|
||||
if (isDisclaimer && (attachMode & FOOTER)) {
|
||||
if (isDisclaimer) {
|
||||
if (isHtml) {
|
||||
for (string endTag : {BODY_END, HTML_END}) {
|
||||
LOG ("try tag: " << endTag);
|
||||
@ -868,37 +641,12 @@ MainAttachment::substitute (ifstream &mbox, ofstream &outbox, const SizeArg &min
|
||||
}
|
||||
attachP->println (outbox, content);
|
||||
} else {
|
||||
LOG_BUG (true, continue, "eMailShrinker: upload has failed, so can't change" << *attachP);
|
||||
LOG_BUG (true, continue, "eMailShrinker: bug M8: can't change" << *attachP);
|
||||
}
|
||||
outbox.flush ();
|
||||
curPos = attachP->endPos;
|
||||
}
|
||||
|
||||
if (subAttachements.size ()) {
|
||||
streamoff lastPos = subAttachements.back ().endPos;
|
||||
copy (mbox, outbox, curPos, lastPos);
|
||||
curPos = lastPos;
|
||||
}
|
||||
if (attachMode & ATTACHMENT) {
|
||||
LOG ("Add kaz attachment");
|
||||
if (movedContentType.size ()) {
|
||||
copy (mbox, outbox, curPos, endPos);
|
||||
outbox << addedBoundary.substr (0, addedBoundaryMiddleSize) << endl
|
||||
<< KAZ_ATTACHMENT_TEXT_HTML << endl;
|
||||
} else
|
||||
outbox << boundary.substr (0, boundaryMiddleSize) << endl
|
||||
<< KAZ_ATTACHMENT_TEXT_HTML << endl;
|
||||
cerr << "eMailShrinker: force attachment" << endl;
|
||||
string content (KAZ_HTML_CONTENT+htmlDisclaim+BODY_END+HTML_END);
|
||||
base64Encode (content);
|
||||
|
||||
outbox << content << endl;
|
||||
outbox.flush ();
|
||||
}
|
||||
if (!movedContentType.size ())
|
||||
copy (mbox, outbox, curPos, endPos);
|
||||
else
|
||||
outbox << addedBoundary << endl;
|
||||
copy (mbox, outbox, curPos, endPos);
|
||||
outbox.close ();
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,7 @@
|
||||
// knowledge of the CeCILL-B license and that you accept its terms. //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "version.hpp"
|
||||
const std::string kaz::LAST_VERSION_NUM ("2.22");
|
||||
const std::string kaz::LAST_VERSION_DATE ("2024-12-09");
|
||||
const std::string kaz::LAST_VERSION (LAST_VERSION_NUM+" "+LAST_VERSION_DATE+" eMailShrinker");
|
||||
#define LAST_VERSION "2.1 2022-10-30 eMailShrinker"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@ -69,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] [-m {Footer|Attachment|Both}] mbox altered-mbox < url-list" << endl
|
||||
<< " B) " << prog << " [-s size] [-d dirName}] mbox > file-list" << endl
|
||||
<< " C) " << prog << " [-s size] 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
|
||||
@ -106,21 +103,20 @@ static const char *const inputFileC = inputFile.c_str ();
|
||||
|
||||
int
|
||||
main (int argc, char** argv) {
|
||||
// uncomment next line in case of debug parse options
|
||||
// XXX debug before parse options
|
||||
// Log::debug = true;
|
||||
DEF_LOG ("main:", "");
|
||||
prog = argv [0];
|
||||
bool
|
||||
debugFlag (false),
|
||||
helpFlag (false),
|
||||
versionFlag (false),
|
||||
updateListFlag (false),
|
||||
useTheForceLuke (false),
|
||||
listFlag (false),
|
||||
debugFlag (false);
|
||||
listFlag (false);
|
||||
string inputName, outputName;
|
||||
bfs::path extractDir (bfs::temp_directory_path ());
|
||||
SizeArg minAttachSize ("48 Ki");
|
||||
AttachMode attachMode (FOOTER);
|
||||
|
||||
try {
|
||||
mainDescription.add_options ()
|
||||
@ -129,7 +125,6 @@ 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 ()
|
||||
@ -202,11 +197,9 @@ main (int argc, char** argv) {
|
||||
attachment.markSignificant (minAttachSize, mbox);
|
||||
mbox.close ();
|
||||
|
||||
if (listFlag) {
|
||||
if (listFlag)
|
||||
// debug
|
||||
cerr << attachment;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (updateListFlag) {
|
||||
// case update
|
||||
@ -224,15 +217,11 @@ main (int argc, char** argv) {
|
||||
showTime ("Extraction");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 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, attachMode);
|
||||
attachment.substitute (mbox, outbox, minAttachSize);
|
||||
showTime ("Substitution");
|
||||
return 0;
|
||||
}
|
||||
|
294
src/cpp/jirafeauAPI.cpp
Normal file
294
src/cpp/jirafeauAPI.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright KAZ 2021 //
|
||||
// //
|
||||
// contact (at) kaz.bzh //
|
||||
// //
|
||||
// This software is a filter to shrink email by attachment extraction. //
|
||||
// //
|
||||
// This software is governed by the CeCILL-B license under French law and //
|
||||
// abiding by the rules of distribution of free software. You can use, //
|
||||
// modify and/or redistribute the software under the terms of the //
|
||||
// CeCILL-B license as circulated by CEA, CNRS and INRIA at the following //
|
||||
// URL "http://www.cecill.info". //
|
||||
// //
|
||||
// As a counterpart to the access to the source code and rights to copy, //
|
||||
// modify and redistribute granted by the license, users are provided //
|
||||
// only with a limited warranty and the software's author, the holder of //
|
||||
// the economic rights, and the successive licensors have only limited //
|
||||
// liability. //
|
||||
// //
|
||||
// In this respect, the user's attention is drawn to the risks associated //
|
||||
// with loading, using, modifying and/or developing or reproducing the //
|
||||
// software by the user in light of its specific status of free software, //
|
||||
// that may mean that it is complicated to manipulate, and that also //
|
||||
// therefore means that it is reserved for developers and experienced //
|
||||
// professionals having in-depth computer knowledge. Users are therefore //
|
||||
// encouraged to load and test the software's suitability as regards //
|
||||
// their requirements in conditions enabling the security of their //
|
||||
// systems and/or data to be ensured and, more generally, to use and //
|
||||
// operate it in the same conditions as regards security. //
|
||||
// //
|
||||
// The fact that you are presently reading this means that you have had //
|
||||
// knowledge of the CeCILL-B license and that you accept its terms. //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define LAST_VERSION "1.1 2022-10-30 jirafeauAPI"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
#include <chrono>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "kazDebug.hpp"
|
||||
#include "kazMisc.hpp"
|
||||
#include "SizeArg.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace boost::program_options;
|
||||
using namespace kaz;
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
// ================================================================================
|
||||
static options_description mainDescription ("Main options", getCols ());
|
||||
static options_description hide ("Hidded options", getCols ());
|
||||
static char *prog = NULL;
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
usage (const string &msg = "", const bool &hidden = false) {
|
||||
if (!msg.empty ()) {
|
||||
cout << msg << endl;
|
||||
exit (1);
|
||||
}
|
||||
cout << endl
|
||||
<< "Usage: " << endl
|
||||
<< " A) " << prog << " [-s size] [-t period] [-c content-type] [-n attachName] [-f server] send file [password] > url,delCode" << endl
|
||||
<< " B) " << prog << " [-t period] [-f server] update ref > dealine" << endl
|
||||
<< endl << " store ficle" << endl << endl
|
||||
<< " A: send file (options : s, t)" << endl
|
||||
<< " B: update deadline (options : t) " << endl
|
||||
<< endl << mainDescription
|
||||
<< endl;
|
||||
if (hidden)
|
||||
cout << hide << endl;
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
version () {
|
||||
cout << LAST_VERSION << " KAZ team production (https://kaz.bzh/)" << endl;
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static auto startPrg = std::chrono::high_resolution_clock::now ();
|
||||
void
|
||||
showTime (string msg) {
|
||||
using namespace std::chrono;
|
||||
static auto stopPrg = high_resolution_clock::now ();
|
||||
|
||||
cerr << msg << " done in " << ns2string (duration_cast<duration<double> > (stopPrg-startPrg).count ()) << endl;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
static size_t
|
||||
WriteCallback (void *contents, size_t size, size_t nmemb, void *userp) {
|
||||
((std::string*) userp)->append ((char*) contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
static const string inputFile = "input-file";
|
||||
static const char *const inputFileC = inputFile.c_str ();
|
||||
|
||||
int
|
||||
main (int argc, char** argv) {
|
||||
// XXX debug before parse options
|
||||
// Log::debug = true;
|
||||
DEF_LOG ("main:", "");
|
||||
prog = argv [0];
|
||||
bool
|
||||
debugFlag (false),
|
||||
helpFlag (false),
|
||||
versionFlag (false),
|
||||
useTheForceLuke (false);
|
||||
enum JirCmd { SEND, UPDATE } jirCmd;
|
||||
string
|
||||
inputFileName,
|
||||
password,
|
||||
contentType,
|
||||
attachName,
|
||||
urlBase ("http://file.kaz.bzh"),
|
||||
uploadPage ("/a.php"),
|
||||
updatePage ("/a.php"),
|
||||
minimumAvailability ("month"),
|
||||
proxy;
|
||||
|
||||
SizeArg maxUploadSize ("100 Mi");
|
||||
|
||||
try {
|
||||
mainDescription.add_options ()
|
||||
("help,h", bool_switch (&helpFlag), "produce this help message")
|
||||
("version,v", bool_switch (&versionFlag), "display version information")
|
||||
("contentType,c", value<string> (&contentType)->default_value (contentType), "content-type of the sended file")
|
||||
("attachName,n", value<string> (&attachName)->default_value (attachName), "force attachment name")
|
||||
("minimumAvailability,t", value<string> (&minimumAvailability)->default_value (minimumAvailability), "minimum period of available download")
|
||||
("maxUploadSize,s", value<SizeArg> (&maxUploadSize)->default_value (maxUploadSize), "maximum upload size")
|
||||
("file server registery,f", value<string> (&urlBase)->default_value (urlBase), "server where file are temporary stored")
|
||||
;
|
||||
|
||||
hide.add_options ()
|
||||
("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> (&uploadPage)->default_value (uploadPage), "upload page")
|
||||
("updatePage,v", value<string> (&updatePage)->default_value (updatePage), "update page")
|
||||
;
|
||||
|
||||
options_description cmd ("All options");
|
||||
cmd.add (mainDescription).add (hide).add_options ()
|
||||
(inputFileC, value<vector<string> > (), "input")
|
||||
;
|
||||
positional_options_description p;
|
||||
p.add (inputFileC, -1);
|
||||
variables_map vm;
|
||||
basic_parsed_options<char> parsed = command_line_parser (argc, argv).options (cmd).positional (p).run ();
|
||||
store (parsed, vm);
|
||||
notify (vm);
|
||||
|
||||
if (debugFlag) {
|
||||
#ifdef DISABLE_LOG
|
||||
cerr << "No debug option available (was compiled with -DDISABLE_LOG)" << endl;
|
||||
#endif
|
||||
}
|
||||
Log::debug = debugFlag;
|
||||
|
||||
if (useTheForceLuke)
|
||||
usage ("", true);
|
||||
if (versionFlag)
|
||||
version ();
|
||||
if (helpFlag)
|
||||
usage ();
|
||||
|
||||
if (vm.count (inputFileC)) {
|
||||
vector<string> var = vm[inputFileC].as<vector<string> > ();
|
||||
int nbArgs = vm[inputFileC].as<vector<string> > ().size ();
|
||||
if (!nbArgs)
|
||||
usage ("No command");
|
||||
if (var [0].compare ("send") == 0)
|
||||
jirCmd = SEND;
|
||||
else if (var [0].compare ("update") == 0)
|
||||
jirCmd = UPDATE;
|
||||
else
|
||||
usage ("Unknown command ("+var [0]+")");
|
||||
if (nbArgs < 2)
|
||||
usage ("no input file");
|
||||
inputFileName = var [1];
|
||||
if (nbArgs == 3)
|
||||
password = var [2];
|
||||
if (nbArgs > 3)
|
||||
usage ("Too much arguments");
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
cerr << "error: " << e.what() << endl;
|
||||
usage ();
|
||||
return 1;
|
||||
} catch (...) {
|
||||
cerr << "Exception of unknown type!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (inputFileName.empty ())
|
||||
usage ("no input");
|
||||
|
||||
CURL *easyhandle = curl_easy_init ();
|
||||
if (! easyhandle) {
|
||||
cerr << "no curl" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
string readBuffer;
|
||||
if (proxy.length ())
|
||||
curl_easy_setopt(easyhandle, CURLOPT_PROXY, proxy.c_str ());
|
||||
curl_easy_setopt (easyhandle, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt (easyhandle, CURLOPT_WRITEDATA, &readBuffer);
|
||||
curl_mime *multipart = curl_mime_init (easyhandle);
|
||||
curl_mimepart *part = nullptr;
|
||||
|
||||
switch (jirCmd) {
|
||||
case SEND: {
|
||||
LOG ("SEND: " << (urlBase+uploadPage));
|
||||
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+uploadPage).c_str ());
|
||||
|
||||
LOG ("maxUploadSize: " << maxUploadSize);
|
||||
long uploadsize = (size_t) maxUploadSize;
|
||||
curl_easy_setopt (easyhandle, CURLOPT_INFILESIZE, uploadsize);
|
||||
|
||||
LOG ("time: " << minimumAvailability);
|
||||
part = curl_mime_addpart (multipart);
|
||||
curl_mime_name (part, "time");
|
||||
curl_mime_data (part, minimumAvailability.c_str (), CURL_ZERO_TERMINATED);
|
||||
|
||||
if (password.size ()) {
|
||||
LOG ("key: " << password);
|
||||
part = curl_mime_addpart (multipart);
|
||||
curl_mime_name (part, "key");
|
||||
curl_mime_data (part, password.c_str (), CURL_ZERO_TERMINATED);
|
||||
}
|
||||
|
||||
LOG ("inputFileName: " << bfs::path (inputFileName).filename ());
|
||||
part = curl_mime_addpart (multipart);
|
||||
curl_mime_name (part, "file");
|
||||
if (contentType.length ()) {
|
||||
LOG ("contentType: " << contentType);
|
||||
curl_mime_type (part, contentType.c_str ());
|
||||
}
|
||||
if (attachName.empty ()) {
|
||||
attachName = bfs::path (inputFileName).filename ().c_str ();
|
||||
LOG ("attachName: " << attachName);
|
||||
}
|
||||
curl_mime_filename (part, attachName.c_str ());
|
||||
FILE *fp = fopen (inputFileName.c_str (), "r");
|
||||
fseek (fp, 0L, SEEK_END);
|
||||
long int fsize (ftell (fp));
|
||||
fseek (fp, 0L, SEEK_SET);
|
||||
curl_mime_data_cb (part, fsize,
|
||||
(curl_read_callback) fread,
|
||||
(curl_seek_callback) fseek,
|
||||
NULL, //(curl_seek_callback) fclose,
|
||||
fp);
|
||||
}
|
||||
break;
|
||||
|
||||
case UPDATE: {
|
||||
LOG ("UPDATE: " << (urlBase+updatePage));
|
||||
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+updatePage).c_str ());
|
||||
|
||||
LOG ("h: " << inputFileName);
|
||||
part = curl_mime_addpart (multipart);
|
||||
curl_mime_name (part, "h");
|
||||
curl_mime_data (part, inputFileName.c_str (), CURL_ZERO_TERMINATED);
|
||||
|
||||
LOG ("u: " << minimumAvailability);
|
||||
part = curl_mime_addpart (multipart);
|
||||
curl_mime_name (part, "u");
|
||||
curl_mime_data (part, minimumAvailability.c_str (), CURL_ZERO_TERMINATED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
curl_easy_setopt (easyhandle, CURLOPT_MIMEPOST, multipart);
|
||||
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;
|
||||
}
|
||||
|
||||
// ================================================================================
|
@ -50,7 +50,7 @@ using namespace kaz;
|
||||
|
||||
static const string::size_type MAX_QUOTED_PRINTABLE_SIZE (78);
|
||||
|
||||
const char *const kaz::base64Chars =
|
||||
const char *const kaz::base64Chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
@ -65,14 +65,6 @@ const string kaz::availableURLChars =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"~";
|
||||
|
||||
const regex kaz::encodedWordRegex ("\\s*=\\?" // flag begin
|
||||
"([0-9A-Za-z!#$%&'+^_`{}~-]+)" // charset
|
||||
"\\?" // flag sep
|
||||
"([QqBb])" // quoted our base64
|
||||
"\\?" // flag sep
|
||||
"([^ ?]+)" // encoded string
|
||||
"\\?=\\s*"); // flag end
|
||||
|
||||
|
||||
// ================================================================================
|
||||
uint16_t
|
||||
@ -105,7 +97,7 @@ kaz::ns2string (const double &delta) {
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::replaceAll (string& str, const string &from, const string &to) {
|
||||
DEF_LOG ("kazMisc::replaceAll", "form: " << from << " to: " << to);
|
||||
DEF_LOG ("kaz::replaceAll", "form: " << from << " to: " << to);
|
||||
if (str.empty () || from.empty ())
|
||||
return;
|
||||
for (string::size_type startPos (0);
|
||||
@ -116,7 +108,7 @@ kaz::replaceAll (string& str, const string &from, const string &to) {
|
||||
|
||||
void
|
||||
kaz::replaceAll (string& str, const map<const string, const string> &subst) {
|
||||
DEF_LOG ("kazMisc::replaceAll", "str: " << str.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::replaceAll", "str: " << str);
|
||||
for (map<const string, const string>::const_iterator it = subst.begin (); it != subst.end (); ++it)
|
||||
replaceAll (str, it->first, it->second);
|
||||
}
|
||||
@ -124,16 +116,16 @@ kaz::replaceAll (string& str, const map<const string, const string> &subst) {
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::toLower (string &content) {
|
||||
DEF_LOG ("kazMisc::toLower", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::toLower", "content: " << content);
|
||||
static locale loc;
|
||||
for (string::size_type i = 0; i < content.length (); ++i)
|
||||
content [i] = tolower (content[i], loc);
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
const string &
|
||||
kaz::toUpperIfNeed (const string &src, string &tmp) {
|
||||
DEF_LOG ("kazMisc::toUpperIfNeed", "src: " << src);
|
||||
DEF_LOG ("kaz::toUpperIfNeed", "src: " << src);
|
||||
for (string::const_iterator it = src.begin (); it != src.end (); ++it)
|
||||
if (*it != toupper (*it)) {
|
||||
tmp.reserve ();
|
||||
@ -151,7 +143,7 @@ caseInsensitiveCharCompare (char a, char b) {
|
||||
|
||||
string::size_type
|
||||
kaz::caseInsensitiveFind (const string& s, const string& pattern, const string::size_type &pos) {
|
||||
DEF_LOG ("kazMisc::caseInsensitiveFind", "pattern: " << pattern << " pos: " << pos << " s: " << s.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::caseInsensitiveFind", "pattern: " << pattern << " pos: " << pos << " s: " << s);
|
||||
string tmp;
|
||||
const string &upperPattern (toUpperIfNeed (pattern, tmp));
|
||||
LOG ("pattern: " << upperPattern);
|
||||
@ -164,7 +156,7 @@ kaz::caseInsensitiveFind (const string& s, const string& pattern, const string::
|
||||
|
||||
string::size_type
|
||||
kaz::caseInsensitiveRFind (const string& s, const string& pattern, const string::size_type &pos) {
|
||||
DEF_LOG ("kazMisc::caseInsensitiveRFind", "pattern: " << pattern << " pos: " << pos << " s: " << s.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::caseInsensitiveRFind", "pattern: " << pattern << " pos: " << pos << " s: " << s);
|
||||
string tmp;
|
||||
const string &upperPattern (toUpperIfNeed (pattern, tmp));
|
||||
LOG ("pattern: " << upperPattern);
|
||||
@ -175,55 +167,43 @@ kaz::caseInsensitiveRFind (const string& s, const string& pattern, const string:
|
||||
return s.rend () - it - pattern.length ();
|
||||
}
|
||||
|
||||
string
|
||||
kaz::boundaryGen (const int &size) {
|
||||
static const char alphanum[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
string result;
|
||||
result.reserve (size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
result += alphanum[rand() % (sizeof (alphanum) - 1)];
|
||||
return result;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
template<char delim>
|
||||
void
|
||||
kaz::quotedDecode (string &content) {
|
||||
DEF_LOG ("kazMisc::quotedDecode", "delim: " << delim << " content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::quotedDecode", "delim: " << delim << " content: " << content);
|
||||
string::size_type len (content.length ());
|
||||
if (!len)
|
||||
return;
|
||||
LOG ("len: " << len);
|
||||
string::iterator p (content.begin ()), q (p);
|
||||
for ( ;
|
||||
p < content.end ();
|
||||
++p, ++q) {
|
||||
p < content.end ();
|
||||
++p, ++q) {
|
||||
if (*p != delim) {
|
||||
*q = *p;
|
||||
continue;
|
||||
}
|
||||
if (p+1 < content.end () && *(p+1) == '\n') {
|
||||
LOG_BUG (q == content.begin (), ++p;continue, "kazMisc::quotedDecode bug: bad quoted-printable format. (start with '=', delim: " << int (delim) << " content: " << content.substr (0, 100) << "...)");
|
||||
|
||||
LOG_BUG (q == content.begin (), ++p;continue, "kazMisc::quotedDecode bug: bad quoted-printable format. (start with '=', content: " << content << ")");
|
||||
++p;
|
||||
--q;
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_BUG (p+3 > content.end () || !isxdigit (p[1]) || !isxdigit (p[2]), return, "kazMisc::quotedDecode bug: bad quoted-printable format. (delim: " << int (delim) << " p:" << content.substr (p-content.begin (), 3) << " content: " << content.substr (0, 100) << "... len: " << len << ")");
|
||||
LOG_BUG (p+3 > content.end () || !isxdigit (p[1]) || !isxdigit (p[2]), return, "kazMisc::quotedDecode bug: bad quoted-printable format. (content: " << content << ")");
|
||||
*q = (char) ((getHexaVal (p[1]) << 4) + getHexaVal (p[2]));
|
||||
p += 2;
|
||||
}
|
||||
content.resize (q-content.begin ());
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::quotedEncode (string &content) {
|
||||
DEF_LOG ("kazMisc::quotedDecode", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::quotedDecode", "content: " << content);
|
||||
string::size_type nbQuoted (0);
|
||||
for (string::const_iterator it = content.begin (); it != content.end (); ++it)
|
||||
if (isQuotedPrintable (*it))
|
||||
@ -266,36 +246,30 @@ kaz::quotedEncode (string &content) {
|
||||
++cols;
|
||||
}
|
||||
content.swap (result);
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::base64Decode (string &content) {
|
||||
DEF_LOG ("kazMisc::base64Decode", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::base64Decode", "content: " << content);
|
||||
string::size_type len (content.length ());
|
||||
if (!len)
|
||||
return;
|
||||
LOG ("len: " << len);
|
||||
unsigned char buff[4];
|
||||
int idx = 0;
|
||||
string::iterator p (content.begin ()), q (p), lastOK (p);
|
||||
string::iterator p (content.begin ()), q (p);
|
||||
for (;
|
||||
p < content.end ();
|
||||
++p) {
|
||||
char c = *p;
|
||||
if (c == '=')
|
||||
break;
|
||||
if (c == '\n') {
|
||||
lastOK = p;
|
||||
if (c == '\n')
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isBase64 (c)) {
|
||||
content.resize (lastOK-content.begin ());
|
||||
LOG ("kazMisc::base64Decode bug: bad base64 format. (content: " << content.substr (0, 100) << "...)");
|
||||
return;
|
||||
}
|
||||
LOG_BUG (!isBase64 (c), return, "kazMisc::base64Decode bug: bad base64 format. (content: " << content << ")");
|
||||
buff [idx] = getBase64Val (c);
|
||||
if (++idx != 4)
|
||||
continue;
|
||||
@ -310,19 +284,20 @@ kaz::base64Decode (string &content) {
|
||||
buff [j] = 0;
|
||||
*q = buff [0] << 2 | (buff [1] & 0x30) >> 4;
|
||||
++q;
|
||||
if (idx > 2) {
|
||||
--idx;
|
||||
if (idx) {
|
||||
*q = buff [1] << 4 | (buff [2] & 0x3c) >> 2;
|
||||
++q;
|
||||
}
|
||||
}
|
||||
content.resize (q-content.begin ());
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::base64Encode (string &content) {
|
||||
DEF_LOG ("kazMisc::base64Encode", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::base64Encode", "content: " << content);
|
||||
string::size_type length (content.length ());
|
||||
std::string result;
|
||||
result.reserve ((length + 2) / 3 * 4 + length / MAX_QUOTED_PRINTABLE_SIZE + 1);
|
||||
@ -352,13 +327,13 @@ kaz::base64Encode (string &content) {
|
||||
}
|
||||
}
|
||||
content = result;
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::iso2utf (string &content) {
|
||||
DEF_LOG ("kazMisc::iso2utf", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::iso2utf", "content: " << content);
|
||||
string::size_type len (content.length ());
|
||||
if (!len)
|
||||
return;
|
||||
@ -384,97 +359,79 @@ kaz::iso2utf (string &content) {
|
||||
if (p == q)
|
||||
break;
|
||||
}
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::encodedWordDecode (string &content) {
|
||||
kaz::encodedWord (string &content) {
|
||||
// rfc2047
|
||||
DEF_LOG ("kazMisc::encodedWordDecode", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::extendedWord", "content: " << content);
|
||||
string::size_type charsetPos = content.find ("=?");
|
||||
if (charsetPos == string::npos)
|
||||
return;
|
||||
LOG ("charsetPos: " << charsetPos);
|
||||
|
||||
LOG_BUG (charsetPos != 0, return, "kazMisc::extendedWord bug: =? not at begin pos. (content: " << content << ")");
|
||||
string result;
|
||||
auto pos (0);
|
||||
sregex_iterator ewItEnd;
|
||||
for (sregex_iterator ewIt (content.begin (), content.end (), encodedWordRegex);
|
||||
ewIt != ewItEnd;
|
||||
++ewIt) {
|
||||
smatch m = *ewIt;
|
||||
if (pos != m.position ()) {
|
||||
result += content.substr (pos, m.position () - pos);
|
||||
LOG ("stantad " << content.substr (pos, m.position () - pos));
|
||||
}
|
||||
string encoded (m[3]);
|
||||
replace (encoded.begin (), encoded.end (), '_', ' ');
|
||||
for ( ;
|
||||
(charsetPos = content.find ("=?", charsetPos)) != string::npos;
|
||||
) {
|
||||
string::size_type modePos = content.find ("?", charsetPos+2);
|
||||
|
||||
LOG ("charset: " << m[1] << " mode: " << m[2] << " string: " << encoded);
|
||||
LOG_BUG (modePos == string::npos, return, "kazMisc::extendedWord bug: no end chartset. (content: " << content << ")");
|
||||
string::size_type contentPos = content.find ("?", modePos+1);
|
||||
|
||||
switch (m[2].str ()[0]) {
|
||||
LOG_BUG (contentPos != modePos+2, return, "kazMisc::extendedWord bug: no end chartset. (content: " << content << ")");
|
||||
string::size_type endPos = content.find ("?=", contentPos+1);
|
||||
|
||||
LOG_BUG (endPos == string::npos, return, "kazMisc::extendedWord bug: no end chartset. (content: " << content << ")");
|
||||
string tmp (content.substr (contentPos+1, endPos-contentPos-1));
|
||||
switch (content [modePos+1]) {
|
||||
case 'B':
|
||||
case 'b':
|
||||
base64Decode (encoded);
|
||||
base64Decode (tmp);
|
||||
break;
|
||||
case 'Q':
|
||||
case 'q':
|
||||
quotedDecode (encoded);
|
||||
quotedDecode (tmp);
|
||||
break;
|
||||
default:
|
||||
|
||||
LOG_BUG (true, return, "kazMisc::encodedWordDecode bug: unknown mode. (mode: " << m[2] << ")");
|
||||
LOG_BUG (true, return, "kazMisc::extendedWord bug: unknown mode. (mode: " << content [modePos+1] << ")");
|
||||
}
|
||||
LOG ("decoded: " << encoded);
|
||||
string charset (m[1]);
|
||||
LOG ("tmp: " << tmp);
|
||||
string charset (content.substr (charsetPos, modePos-charsetPos-2));
|
||||
toLower (charset);
|
||||
if (! caseInsensitiveFind (charset, "ISO"))
|
||||
iso2utf (encoded);
|
||||
result += encoded;
|
||||
pos = m.position () + m.str ().length ();
|
||||
iso2utf (tmp);
|
||||
result += tmp;
|
||||
charsetPos = endPos+2;
|
||||
}
|
||||
content = result + content.substr (pos);
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
content = result;
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::charsetValueDecode (string &content) {
|
||||
kaz::charsetValue (string &content) {
|
||||
// rfc2184
|
||||
DEF_LOG ("kazMisc::charsetValueDecode", "content: " << content.substr (0, 100) << "...");
|
||||
DEF_LOG ("kaz::charsetValue", "content: " << content);
|
||||
string::size_type langPos = content.find ("'");
|
||||
|
||||
LOG_BUG (langPos == string::npos, return, "kazMisc::charsetValueDecode bug: no '. (content: " << content.substr (0, 100) << "...)");
|
||||
LOG_BUG (langPos == string::npos, return, "kazMisc::charsetValue bug: no '. (content: " << content << ")");
|
||||
string::size_type contentPos = content.find ("'", langPos+1);
|
||||
|
||||
LOG_BUG (contentPos == string::npos, return, "kazMisc::charsetValueDecode bug: no double '. (content: " << content.substr (0, 100) << "...)");
|
||||
LOG_BUG (contentPos == string::npos, return, "kazMisc::charsetValue bug: no double '. (content: " << content << ")");
|
||||
string tmp (content.substr (contentPos+1));
|
||||
quotedDecode<'%'> (tmp);
|
||||
LOG ("tmp: " << tmp.substr (0, 100) << "...");
|
||||
LOG ("tmp: " << tmp);
|
||||
string charset (content.substr (0, langPos));
|
||||
toLower (charset);
|
||||
if (! caseInsensitiveFind (charset, "ISO"))
|
||||
iso2utf (tmp);
|
||||
content = tmp;
|
||||
LOG ("content: " << content.substr (0, 100) << "...");
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
kaz::removeQuote (string &content) {
|
||||
if (content.empty () || content [0] != '"')
|
||||
return;
|
||||
string::size_type stop = (1);
|
||||
for (;;) {
|
||||
stop = content.find ('"', stop);
|
||||
if (stop == string::npos || content [stop-1] != '\\')
|
||||
break;
|
||||
++stop;
|
||||
}
|
||||
content = (stop != string::npos) ?
|
||||
content.substr (1, stop-1) :
|
||||
content.substr (1);
|
||||
LOG ("content: " << content);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
|
@ -1,223 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright KAZ 2021 //
|
||||
// //
|
||||
// contact (at) kaz.bzh //
|
||||
// //
|
||||
// This software is a filter to shrink email by attachment extraction. //
|
||||
// //
|
||||
// This software is governed by the CeCILL-B license under French law and //
|
||||
// abiding by the rules of distribution of free software. You can use, //
|
||||
// modify and/or redistribute the software under the terms of the //
|
||||
// CeCILL-B license as circulated by CEA, CNRS and INRIA at the following //
|
||||
// URL "http://www.cecill.info". //
|
||||
// //
|
||||
// As a counterpart to the access to the source code and rights to copy, //
|
||||
// modify and redistribute granted by the license, users are provided //
|
||||
// only with a limited warranty and the software's author, the holder of //
|
||||
// the economic rights, and the successive licensors have only limited //
|
||||
// liability. //
|
||||
// //
|
||||
// In this respect, the user's attention is drawn to the risks associated //
|
||||
// with loading, using, modifying and/or developing or reproducing the //
|
||||
// software by the user in light of its specific status of free software, //
|
||||
// that may mean that it is complicated to manipulate, and that also //
|
||||
// therefore means that it is reserved for developers and experienced //
|
||||
// professionals having in-depth computer knowledge. Users are therefore //
|
||||
// encouraged to load and test the software's suitability as regards //
|
||||
// their requirements in conditions enabling the security of their //
|
||||
// systems and/or data to be ensured and, more generally, to use and //
|
||||
// operate it in the same conditions as regards security. //
|
||||
// //
|
||||
// The fact that you are presently reading this means that you have had //
|
||||
// knowledge of the CeCILL-B license and that you accept its terms. //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include "kazDebug.hpp"
|
||||
#include "kazMisc.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace boost::program_options;
|
||||
using namespace kaz;
|
||||
|
||||
#define CONSOLE(expr) {if (!quietFlag) {std::cerr << Log::getLocalTimeStr () << " " << expr << std::endl << std::flush; }}
|
||||
|
||||
// ================================================================================
|
||||
const string LAST_VERSION_NUM ("3.0");
|
||||
const string LAST_VERSION_DATE ("2024-01-01");
|
||||
const string LAST_VERSION (LAST_VERSION_NUM+" "+LAST_VERSION_DATE+" server");
|
||||
|
||||
#define PORT 8080
|
||||
|
||||
const string BASH ("/bin/bash");
|
||||
const string FILTER_CMD ("/home/filter/testCopyInOut.sh");
|
||||
|
||||
// ================================================================================
|
||||
static options_description mainDescription ("Main options", getCols ());
|
||||
static options_description hide ("Hidded options", getCols ());
|
||||
static const char *prog = NULL;
|
||||
|
||||
// ================================================================================
|
||||
void
|
||||
usage (const string &msg = "", const bool &hidden = false) {
|
||||
if (!msg.empty ()) {
|
||||
cout << msg << endl;
|
||||
exit (1);
|
||||
}
|
||||
cout << endl
|
||||
<< "Usage: " << endl
|
||||
<< " " << prog << " [-p port] [-f filterFileName.sh]" << endl
|
||||
<< endl << mainDescription
|
||||
<< endl;
|
||||
if (hidden)
|
||||
cout << hide << endl;
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
version () {
|
||||
cout << LAST_VERSION << " KAZ team production (https://kaz.bzh/)" << endl;
|
||||
exit (0);
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
int
|
||||
main (int argc, const char *argv[], char **envp) {
|
||||
// uncomment next line in case of debug parse options
|
||||
// Log::debug = true;
|
||||
DEF_LOG ("main:", LAST_VERSION);
|
||||
prog = argv [0];
|
||||
bool
|
||||
helpFlag (false),
|
||||
versionFlag (false),
|
||||
quietFlag (false),
|
||||
useTheForceLuke (false),
|
||||
debugFlag (false);
|
||||
int port (PORT);
|
||||
string filterFileName (FILTER_CMD);
|
||||
|
||||
try {
|
||||
mainDescription.add_options ()
|
||||
("help,h", bool_switch (&helpFlag), "produce this help message")
|
||||
("version,v", bool_switch (&versionFlag), "display version information")
|
||||
("quiet,q", bool_switch (&quietFlag), "quiet mode")
|
||||
("port,p", value<int> (&port)->default_value (port), "server port number")
|
||||
("filter,f", value<string> (&filterFileName)->default_value (filterFileName), "filter file name script")
|
||||
;
|
||||
|
||||
hide.add_options ()
|
||||
("useTheForceLuke", bool_switch (&useTheForceLuke), "display hidded options")
|
||||
("debug,g", bool_switch (&debugFlag), "debug mode")
|
||||
;
|
||||
options_description cmd ("All options");
|
||||
cmd.add (mainDescription).add (hide).add_options ();
|
||||
|
||||
variables_map vm;
|
||||
store (parse_command_line(argc, argv, cmd), vm);
|
||||
notify (vm);
|
||||
|
||||
if (debugFlag) {
|
||||
#ifdef DISABLE_LOG
|
||||
cerr << "No debug option available (was compiled with -DDISABLE_LOG)" << endl;
|
||||
#endif
|
||||
}
|
||||
Log::debug = debugFlag;
|
||||
|
||||
if (useTheForceLuke)
|
||||
usage ("", true);
|
||||
if (versionFlag)
|
||||
version ();
|
||||
if (helpFlag)
|
||||
usage ();
|
||||
|
||||
|
||||
} catch (std::exception &e) {
|
||||
cerr << "error: " << e.what() << endl;
|
||||
usage ();
|
||||
return 1;
|
||||
} catch (...) {
|
||||
cerr << "Exception of unknown type!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sockaddr_in address;
|
||||
int opt = 1;
|
||||
socklen_t addrlen = sizeof (address);
|
||||
|
||||
LOG ("create socket");
|
||||
int serverSocket (socket (AF_INET, SOCK_STREAM, 0));
|
||||
if (serverSocket < 0) {
|
||||
perror ("socket failed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LOG ("set socket options");
|
||||
if (setsockopt (serverSocket, SOL_SOCKET,
|
||||
SO_REUSEADDR | SO_REUSEPORT, &opt,
|
||||
sizeof (opt))) {
|
||||
perror ("setsockopt");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons (port);
|
||||
|
||||
LOG ("bind");
|
||||
if (bind (serverSocket, (struct sockaddr*)&address, sizeof (address)) < 0) {
|
||||
perror ("bind failed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LOG ("listen");
|
||||
if (listen (serverSocket, 3) < 0) {
|
||||
perror ("listen");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
CONSOLE ("Server started on port " << port);
|
||||
for (;;) {
|
||||
LOG ("accept");
|
||||
int clientSocket (accept (serverSocket, (struct sockaddr*) &address, &addrlen));
|
||||
if (clientSocket < 0) {
|
||||
perror ("accept");
|
||||
// XXX ne pas quitter
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
char *command[] = {const_cast<char *> (BASH.c_str ()),
|
||||
const_cast<char *> (filterFileName.c_str ()), NULL};
|
||||
switch (fork ()) {
|
||||
case -1:
|
||||
perror ("fork");
|
||||
exit (EXIT_FAILURE);
|
||||
case 0:
|
||||
CONSOLE ("New request");
|
||||
close (STDOUT_FILENO);
|
||||
close (STDIN_FILENO);
|
||||
dup2 (clientSocket, STDIN_FILENO);
|
||||
dup2 (clientSocket, STDOUT_FILENO);
|
||||
execve (BASH.c_str (), command, envp);
|
||||
perror ("execve");
|
||||
break;
|
||||
default:
|
||||
close (clientSocket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// XXX condition de sortie ?
|
||||
close (serverSocket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ================================================================================
|
@ -1,118 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright KAZ 2021 //
|
||||
// //
|
||||
// contact (at) kaz.bzh //
|
||||
// //
|
||||
// This software is a filter to shrink email by attachment extraction. //
|
||||
// //
|
||||
// This software is governed by the CeCILL-B license under French law and //
|
||||
// abiding by the rules of distribution of free software. You can use, //
|
||||
// modify and/or redistribute the software under the terms of the //
|
||||
// CeCILL-B license as circulated by CEA, CNRS and INRIA at the following //
|
||||
// URL "http://www.cecill.info". //
|
||||
// //
|
||||
// As a counterpart to the access to the source code and rights to copy, //
|
||||
// modify and redistribute granted by the license, users are provided //
|
||||
// only with a limited warranty and the software's author, the holder of //
|
||||
// the economic rights, and the successive licensors have only limited //
|
||||
// liability. //
|
||||
// //
|
||||
// In this respect, the user's attention is drawn to the risks associated //
|
||||
// with loading, using, modifying and/or developing or reproducing the //
|
||||
// software by the user in light of its specific status of free software, //
|
||||
// that may mean that it is complicated to manipulate, and that also //
|
||||
// therefore means that it is reserved for developers and experienced //
|
||||
// professionals having in-depth computer knowledge. Users are therefore //
|
||||
// encouraged to load and test the software's suitability as regards //
|
||||
// their requirements in conditions enabling the security of their //
|
||||
// systems and/or data to be ensured and, more generally, to use and //
|
||||
// operate it in the same conditions as regards security. //
|
||||
// //
|
||||
// The fact that you are presently reading this means that you have had //
|
||||
// knowledge of the CeCILL-B license and that you accept its terms. //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "kazDebug.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace kaz;
|
||||
|
||||
const string LAST_VERSION_NUM ("3.0");
|
||||
const string LAST_VERSION_DATE ("2024-01-01");
|
||||
const string LAST_VERSION (LAST_VERSION_NUM+" "+LAST_VERSION_DATE+" testServerRW");
|
||||
|
||||
#define PORT 8080
|
||||
|
||||
int
|
||||
main (int argc, char const* argv[]) {
|
||||
Log::debug = true;
|
||||
DEF_LOG ("main:", LAST_VERSION);
|
||||
|
||||
int clientSocket;
|
||||
struct sockaddr_in serv_addr;
|
||||
LOG ("create socket");
|
||||
if ((clientSocket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
cerr << endl << "Socket creation error" << endl;
|
||||
perror ("socket failed");
|
||||
return -1;
|
||||
}
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons (PORT);
|
||||
|
||||
LOG ("check address");
|
||||
if (inet_pton (AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
|
||||
cerr << endl << "Invalid address / Address not supported" << endl;
|
||||
perror ("socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG ("connect on " << PORT);
|
||||
if (connect (clientSocket, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
|
||||
cerr << endl << "Connection Failed" << endl;
|
||||
perror ("socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool end (false);
|
||||
LOG ("send original email (end with QUIT)");
|
||||
for (;;) {
|
||||
if (!end) {
|
||||
string hello;
|
||||
cin >> hello;
|
||||
if (hello == "QUIT") {
|
||||
shutdown (clientSocket, SHUT_WR);
|
||||
LOG ("shutdown send");
|
||||
break;
|
||||
}
|
||||
LOG ("avant");
|
||||
hello.push_back ('\n');
|
||||
send (clientSocket, hello.c_str (), hello.size (), 0);
|
||||
LOG ("apres");
|
||||
}
|
||||
}
|
||||
LOG ("receive...");
|
||||
for (;;) {
|
||||
char buffer[1024] = { 0 };
|
||||
ssize_t msgSize (recv (clientSocket, buffer, 1024 - 1, 0));
|
||||
switch (msgSize) {
|
||||
case -1 :
|
||||
perror ("socket failed");
|
||||
return -1;
|
||||
case 0 :
|
||||
LOG ("shutdown receive");
|
||||
close (clientSocket);
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
//cout.write (buffer, msgSize);
|
||||
printf ("%s\n", buffer);
|
||||
}
|
||||
}
|
||||
}
|
@ -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, MULTIPART, RELATED, ALTERNATIVE, SIGNED, KAZ_ATTACH_NAME;
|
||||
static const string contentTypeToken, contentDispositionToken, contentTransferEncodingToken, base64Token, quotedPrintableToken, contentIDToken, PLAIN, HTML, RELATED, ALTERNATIVE;
|
||||
/*! 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, isKazAttachment, isSigned;
|
||||
bool toExtract, toUpdate, toDisclaim;
|
||||
/*! id of an image embedded in mbox */
|
||||
string cid;
|
||||
/*! url to replace the attachment */
|
||||
@ -131,9 +131,7 @@ namespace kaz {
|
||||
/*! recursively marks alternative attachments to be disclaim */
|
||||
void markDisclaim (bool &plainMarked, bool &htmlMarked);
|
||||
/*! recursively marks big attachments to be removed and upated (including disclaim). return true when part need to be updated (can't be extracted). */
|
||||
bool markSignificant (const string &parentMultiProp, const bool &parentSigned, const streamoff &minAttachSize, ifstream &mbox, vector<Attachment *> &allMarkedPtrs);
|
||||
/*! get a copy of mime header */
|
||||
string getMime (ifstream &mbox) const;
|
||||
bool markSignificant (const string &parentMultiProp, const streamoff &minAttachSize, ifstream &mbox, vector<Attachment *> &allMarkedPtrs);
|
||||
/*! get a copy of the content. Base64 is decoded. Quoted-Printable is unwarp and unquoted */
|
||||
string getContent (ifstream &mbox) const;
|
||||
/*! write the content, encoded if necessary (base64 and quoted-printable) */
|
||||
|
@ -44,24 +44,11 @@ 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);
|
||||
|
||||
enum HeaderType { SAME, MIXED, MAIN_PLAIN };
|
||||
extern const string headerTypeLabels[];
|
||||
extern const map<string, HeaderType> headerTypeMap;
|
||||
ostream &operator << (ostream &out, const HeaderType &headerType);
|
||||
istream &operator >> (istream &in, HeaderType &headerType);
|
||||
|
||||
/*! root level of e-mail structure */
|
||||
class MainAttachment : public Attachment {
|
||||
public:
|
||||
/*! text to add in disclaim */
|
||||
static const string templatePlainAddLink, templatePlainAllLink, templatePlainCloudLink, templatePlainFooter, templateHtmlHeader, templateHtmlAddLink, templateHtmlOtherLink, templateHtmlAllLink, templateHtmlCloudLink, templateHtmlFooter;
|
||||
static const string templatePlainAddLink, templatePlainAllLink, templateHtmlHeader, templateHtmlAddLink, templateHtmlOtherLink, templateHtmlAllLink, templateHtmlFooter;
|
||||
|
||||
/*! white space to split a text */
|
||||
static const regex whiteSpaceRegEx;
|
||||
@ -71,10 +58,9 @@ namespace kaz {
|
||||
|
||||
/*! get url from stdin */
|
||||
void readDownloadUrl (string &url);
|
||||
|
||||
/*! get archive url from stdin */
|
||||
void readArchiveUrl ();
|
||||
/*! get cloud url from stdin */
|
||||
void readCloudUrl ();
|
||||
|
||||
/*! location of extracted files */
|
||||
void setExtractDir (const bfs::path &extractDir);
|
||||
@ -97,25 +83,13 @@ namespace kaz {
|
||||
bfs::path extractDir;
|
||||
/*! URL for download archives */
|
||||
string archiveDownloadURL;
|
||||
/*! URL for download cloud */
|
||||
string cloudDownloadURL;
|
||||
/*! if no main text in email can be used to add disclaim */
|
||||
bool emptyEMail;
|
||||
/*! if contain previous kaz attachment */
|
||||
bool previousKazAttachment;
|
||||
/*! no main text in email can be use to add disclaim */
|
||||
bool forceMainText;
|
||||
|
||||
/*! subset in the tree of all attachments to be consider for extraction or modification */
|
||||
vector<Attachment *> allMarkedPtrs;
|
||||
/*! previous links find in mbox */
|
||||
map<string, string> previousLinks;
|
||||
/*! boundary if a mixed section is added including previous and next "--" */
|
||||
string addedBoundary;
|
||||
/*! size of added boundary before the last "--" */
|
||||
streamoff addedBoundaryMiddleSize;
|
||||
/*! moved conten-type headers */
|
||||
string movedContentType;
|
||||
|
||||
|
||||
/*! add link only if no significant value already exist. Trust the values from html.*/
|
||||
void addPrevious (const string &href, const string &name, const bool &trust = false);
|
||||
|
||||
@ -123,16 +97,11 @@ namespace kaz {
|
||||
void extractLinks (const string &extractedPlainKAZ);
|
||||
/*! extract previous links from html-li list. Used by extractPreviousKAZ */
|
||||
void extractLinks (const vector<string> &liOne);
|
||||
/*! extract previous links in mbox on one attachment section. Used by extractPreviousKAZ */
|
||||
void extractPreviousKAZ (string &extractedPlainKAZ, string &extractedHtmlKAZ, ifstream &mbox, const Attachment &attach);
|
||||
/*! extract previous links in mbox. Used by getUpdatedURL and substitute */
|
||||
void extractPreviousKAZ (ifstream &mbox);
|
||||
/*! remove previous links to archive. Used by substitute */
|
||||
void removePreviousArchive ();
|
||||
|
||||
/*! rewrite main headers */
|
||||
void rewriteHeaders (ifstream &mbox, ofstream &outbox, const HeaderType &headerType);
|
||||
|
||||
public:
|
||||
/*! the main attachment in mbox */
|
||||
MainAttachment (ifstream &mbox);
|
||||
@ -146,7 +115,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, AttachMode attachMode);
|
||||
void substitute (ifstream &mbox, ofstream &outbox, const SizeArg &minSize);
|
||||
};
|
||||
|
||||
// ================================================================================
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include <string>
|
||||
#include <ctype.h>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
|
||||
namespace kaz {
|
||||
using namespace std;
|
||||
@ -48,8 +47,6 @@ namespace kaz {
|
||||
extern const char * const base64Chars;
|
||||
/*! set of chars available in URL */
|
||||
extern const string availableURLChars;
|
||||
/*! pattern for encoded words */
|
||||
extern const regex encodedWordRegex;
|
||||
|
||||
// =======================================================================
|
||||
/*! get the width of the terminal */
|
||||
@ -74,9 +71,6 @@ namespace kaz {
|
||||
string::size_type caseInsensitiveFind (const string& s, const string& p, const string::size_type &pos = 0);
|
||||
/*! reverse find upper case of p in upper case of s */
|
||||
string::size_type caseInsensitiveRFind (const string& s, const string& p, const string::size_type &pos = 0);
|
||||
|
||||
string boundaryGen (const int &size);
|
||||
|
||||
/*! side effect to repplace =XX by the char with de haxe value XX. It could be %XX in rfc2184 */
|
||||
template<char delim='='>
|
||||
void quotedDecode (string &content);
|
||||
@ -88,19 +82,17 @@ namespace kaz {
|
||||
void base64Encode (string &content);
|
||||
/*! side effect to change charset of content */
|
||||
void iso2utf (string &content);
|
||||
/*! side effect to get the encoded word according rfc2047 rfc5987 rfc2978 */
|
||||
void encodedWordDecode (string &content);
|
||||
/*! side effect to get the encodedWord according rfc2047 */
|
||||
void encodedWord (string &content);
|
||||
/*! side effect to get the charsetValue according rfc2184 */
|
||||
void charsetValueDecode (string &content);
|
||||
/*! side effect to remove quote */
|
||||
void removeQuote (string &content);
|
||||
void charsetValue (string &content);
|
||||
|
||||
// =======================================================================
|
||||
/*! return if the c need no quote */
|
||||
inline bool
|
||||
isQuotedPrintable (const char &c) {
|
||||
return
|
||||
c == ' ' || (c >= 33 && c <= 126 && c != '=' && c != '.');
|
||||
c == ' ' || c == '\t' || (c >= 33 && c <= 126 && c != '=' && c != '.');
|
||||
// '.' is available in rfc2184 but it avoid to check '.' alone in a line :-)
|
||||
}
|
||||
|
||||
|
@ -1,48 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright KAZ 2021 //
|
||||
// //
|
||||
// contact (at) kaz.bzh //
|
||||
// //
|
||||
// This software is a filter to shrink email by attachment extraction. //
|
||||
// //
|
||||
// This software is governed by the CeCILL-B license under French law and //
|
||||
// abiding by the rules of distribution of free software. You can use, //
|
||||
// modify and/or redistribute the software under the terms of the //
|
||||
// CeCILL-B license as circulated by CEA, CNRS and INRIA at the following //
|
||||
// URL "http://www.cecill.info". //
|
||||
// //
|
||||
// As a counterpart to the access to the source code and rights to copy, //
|
||||
// modify and redistribute granted by the license, users are provided //
|
||||
// only with a limited warranty and the software's author, the holder of //
|
||||
// the economic rights, and the successive licensors have only limited //
|
||||
// liability. //
|
||||
// //
|
||||
// In this respect, the user's attention is drawn to the risks associated //
|
||||
// with loading, using, modifying and/or developing or reproducing the //
|
||||
// software by the user in light of its specific status of free software, //
|
||||
// that may mean that it is complicated to manipulate, and that also //
|
||||
// therefore means that it is reserved for developers and experienced //
|
||||
// professionals having in-depth computer knowledge. Users are therefore //
|
||||
// encouraged to load and test the software's suitability as regards //
|
||||
// their requirements in conditions enabling the security of their //
|
||||
// systems and/or data to be ensured and, more generally, to use and //
|
||||
// operate it in the same conditions as regards security. //
|
||||
// //
|
||||
// The fact that you are presently reading this means that you have had //
|
||||
// knowledge of the CeCILL-B license and that you accept its terms. //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _kaz_version_hpp
|
||||
#define _kaz_version_hpp
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace kaz {
|
||||
// ================================================================================
|
||||
|
||||
extern const std::string LAST_VERSION_NUM, LAST_VERSION_DATE, LAST_VERSION;
|
||||
|
||||
// ================================================================================
|
||||
}
|
||||
|
||||
#endif // _kaz_version_hpp
|
@ -1,25 +0,0 @@
|
||||
**Dépollueur**
|
||||
|
||||
Le dépollueur consiste à extraire les pièces jointes pour les remplacer par des liens de téléchargement temporaire.
|
||||
|
||||
Le logiciel est donc très fortement lié à un logiciel de dépôt de fichier.
|
||||
Le système de dépôt de proposé par Jirafeau à l'avantage de gérer les liens interne en fonction de la signature du contenu (hash).
|
||||
Cela offre plusieurs avantages. les fichiers de même contenu sont factorisés sans que les utilisateurs en aient consciences.
|
||||
L'intégrité des données est inhérente à ce mécanisme, puisque un lien ne va pas faire référence à un autre contenu dans le dépôt.
|
||||
|
||||
A partir du moment où notre dépollueur à une action sur les messages, cela à des conséquences sur l’utilisation d'outils cryptographiques.
|
||||
Le chiffrement de pièces jointes a peu d'incidence. L'information chiffrée se trouve stocké sur un serveur au lieu d'un ordinateur personnel (voir pire un serveur des GAFAM).
|
||||
Ici, l'avantage est que l'information sera détruite au bout d'un temps spécifié.
|
||||
|
||||
La signature, empêche le dépollueur d'intervenir.
|
||||
Dans le cas où l'on souhaite signer ses messages, il faut au préalable déposer ses pièces jointes (hors GAFAM) et faire référence dans le message aux liens de téléchargement.
|
||||
|
||||
|
||||
|
||||
Main Programme:
|
||||
* [eMailShrinker](eMailShrinker_8cpp.html)
|
||||
|
||||
Main classes:
|
||||
* [MainAttachment](classkaz_1_1MainAttachment.html)
|
||||
* [Attachment](classkaz_1_1Attachment.html)
|
||||
|
BIN
structures.odt
BIN
structures.odt
Binary file not shown.
Loading…
Reference in New Issue
Block a user